Developers

Below you'll find information, guides and tutorials helping you get flying with a custom Timekit integration in no time.

Introduction

A brief introduction to the API and core data types.

 

This API reference is focused on server-to-server integrations. If all you need is to make your resources bookable through our widget, please refer to our setting up your first project article.

For a general introduction to working with the API please refer to our API articles.

App specific requests

All endpoints documented here are app specific. This means that all results are from entities located the under the specific app you are requesting for. You can have more than one app on Timekit so keep an eye on which App API-Key you are including in your request since it will determine which app context your requests are made in. You can read more about Timekit apps in our introduction glossary

The Timekit API is organized around REST. Our API is designed to follow common HTTP conventions including response codes to indicate both errors and successful requests. Standard HTTP verbs (GET, POST, PUT, DELETE) are used for all methods, no exceptions.

JSON will be returned in all responses from the API, including error messages.

Root endpoint, versions, and protocol

All API calls should be made to https://api.timekit.io/v2 (note the explicit versioning). The current public version of the API is version 2 and is the only publicly supported version (calls to v1 will result in 404 Not Found).

HTTP over TLS 1.2 is enforced for all calls, so non-secure calls will result in a 301 Moved Permanently pointing to the https URI.

CORS

Our API is intended to be consumed both by browser clients (e.g. SPAs) and servers and supports cross-origin resource sharing. As of right now, JSONP is not supported, but we'd love to hear from you if it's of interest.

UUID as IDs

All IDs used by Timekit are UUIDs. A UUID looks like this: de305d54-75b4-431b-adb2-eb6b9e546014
Read more about uuids here

Timezones

All timezones must be defined by their Area/Location name from the IANA TZ database, for reference see https://en.wikipedia.org/wiki/Tz_database

Examples:

  • Europe/Copenhagen
  • America/Los_Angeles

Undocumented attributes

Some of the endpoints referenced here will return more data than specified in this reference. Do not rely on any undocumented data, since it will be subject to change without notice.

Timestamps

Timestamps are a critical part of Timekit.

 

All timestamps will default be RFC3339 / ATOM formatted, this is also the default input format.

Example:
2017-11-24T08:46:01+00:00

Below are examples of how you generate a RFC 3339 formatted timestamp string.

require 'time'
now = Time.now
isoDate = now.rfc3339
$now = new DateTime();
$isoDate = $now->format(DateTime::RFC3339);
String isoDate = ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT );
DateTime localTime = DateTime.Now;
DateTimeOffset localTimeWithOffset = new DateTimeOffset(localTime, TimeZoneInfo.Local.GetUtcOffset(localTime));
String isoDate = localTimeWithOffset.ToString("yyyy-MM-ddTHH:mm:ssK")
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];   
NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[dateFormatter setLocale:enUSPOSIXLocale];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];

NSDate *now = [NSDate date];
NSString *isoDate = [dateFormatter stringFromDate:now];
let dateFormatter = DateFormatter()
let enUSPosixLocale = Locale(identifier: "en_US_POSIX")
dateFormatter.locale = enUSPosixLocale
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"

let isoDate = dateFormatter.string(from: Date())
import datetime
datetime.datetime.now().isoformat()
now := time.Now()
isoDate := now.Format(time.RFC3339)
function zerofill(value){
  if(value < 10){
    return '0'+value;
  }
  return value;
}
function getRfcOffset(offsetInMinutes){
  var rfcOffset = '-';
  if(offsetInMinutes < 0){
    rfcOffset = '+';
  }
  offsetInMinutes = Math.abs(offsetInMinutes);
  offsetHours = Math.floor(offsetInMinutes / 60);
  rfcOffset += zerofill(offsetHours)+':';
  offsetMinutes = Math.floor(offsetInMinutes % 60);
  rfcOffset += zerofill(offsetMinutes);
  return rfcOffset;
}
var now = new Date();
var rfcDate = now.getUTCFullYear()+'-';
rfcDate += zerofill(now.getMonth()+1)+'-';
rfcDate += zerofill(now.getDate())+'T';
rfcDate += zerofill(now.getHours())+':';
rfcDate += zerofill(now.getMinutes())+':';
rfcDate += zerofill(now.getSeconds());
rfcDate += getRfcOffset(now.getTimezoneOffset())

Custom timestamp formats

With great power comes great resposibility.

Rolling your own timestamp format is a pretty neat feature, just keep in mind that you might loose important data, not least time-zone data may be omitted and you must handle this on your end in such cases.

You can also define the input and output timestamp formatting this these headers:

  • Timekit-OutputTimestampFormat
  • Timekit-InputTimestampFormat
curl --request POST \
  --url 'https://api.timekit.io/v2/availability'
  --header 'Timekit-OutputTimestampFormat: Y-m-d h:ia' \
  --header 'Timekit-InputTimestampFormat: Y/m/d' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
    "resources": ["65795c5c-e155-4a52-a35e-656f4e3a4cbe"],
    "from": "2018/04/24",
    "to": "2018/04/25",
    "length": "1 hour"
  }' \
     

Which will return something like this

{
  "data": [
    {
      "start": "2018-04-24 09:00am",
      "end": "2018-04-24 10:00am",
      "resources": [
        {
          "id": "65795c5c-e155-4a52-a35e-656f4e3a4cb",
          "name": "Marty McFly",
          "timezone": "America\/Los_Angeles"
        }
      ]
    },
    {
      "start": "2018-04-24 10:00am",
      "end": "2018-04-24 11:00am",
      "resources": [
        {
          "id": "65795c5c-e155-4a52-a35e-656f4e3a4cb",
          "name": "Marty McFly",
          "timezone": "America\/Los_Angeles"
        }
      ]
    },
    {
      "start": "2018-04-24 01:00pm",
      "end": "2018-04-24 02:00am",
      "resources": [
        {
          "id": "65795c5c-e155-4a52-a35e-656f4e3a4cb",
          "name": "Marty McFly",
          "timezone": "America\/Los_Angeles"
        }
      ]
    }
  ]
}

Format reference

The data format is defined in the format params, where the following options is available

Format
Description
Examples

d

Day of the month, 2 digits with leading zeros

01 through 31

m

Numeric representation of a month, with leading zeros

01 through 12

Y

A full numeric representation of a year, 4 digits

1999, 2003, 2018

a

Lowercase Ante meridiem and Post meridiem

am or pm

h

12-hour format of an hour with leading zeros

01 through 12

H

24-hour format of an hour with leading zeros

00 through 23

i

Minutes with leading zeros

00 through 59

s

Seconds, with leading zeros

00 through 59

P

Timezone offset to GMT with colon separating hours and minutes

+02:00

O

Timezone offset to GMT

+0200

T

Timezone abbreviation

EST, MDT, AST, UTC

U

Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)

1530171700

l

(Lower-case L) A full textual representation of the day of the week

Sunday through Saturday

D

Day-name abbreviation

Mon through Sun

M

Month-name abbreviation

Jan through Dec

Y-m-d\TH:i:s.000Z

ISO-8601 as Javascript formats dates using Date.toISOString()
Notice that we do not support miliseconds, so we just input three zeros to remain compatible. Also notice that we need to escape the T since it is a reserved character.

2018-06-28T08:00:00.000Z

D, d M Y H:i:s O

RFC-2822

Mon, 21 May 2018 16:01:07 +0200

l, d-M-y H:i:s T

RFC-850

Thursday, 28-Jun-18 08:00:00 AST

App authentication

 

Before you can start using our API you must sign up via our admin interface. The admin interface is also where you find your App API key that you need to authenticate with the API.

What's an app?

From our Glossary:

"On Timekit, an app is simply an isolated collection of projects, resources and bookings. Each app has its own billing plan and app owners. Often you would only need a single app to build your booking experience but some scenarios can require multiple apps setups."

Read the full glossary article here.

HTTP Basic Authentication

We use Basic Authentication over HTTPS: https://en.wikipedia.org/wiki/Basic_access_authentication.

App API Key authentication

In Timekit, each of your apps has its own key which is used for authentication. You find this key in the Timekit admin under API Settings. API-Key authentication is different from normal basic authentication, in that there is no email/user-name value for the API-Key and so authentication only uses the key value as you would normally use the password.

Example authentication request via App API-Key

curl --request GET \
  --url https://api.timekit.io/v2/bookings \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7

In other words do not input anything for the user-name part of basic authentication.

Notice the prefixing colon!

Authenticating with API-Key does not use the email part of basic authentication, but in order to remain compatible we need to prefix the API-Key with colon, which will tell cURL that the email is an empty string. Do note that this is specific to the cURL implementation!

Using the "Try It" functionality

The "Try It" functionality lets you try each endpoint against Timekits API, we recommend using an api key for an app in test mode!
You need to set the "Authorization" header and this must be base64 encoded as per the Basic authentication scheme. You can base64 encode your api-key here: https://codebeautify.org/base64-encode remember to prefix the key with a colon!.

Example:
If your API Key is test_api_key_foobar you must base64 encode :test_api_key_foobar which will result in the value OnRlc3RfYXBpX2tleV9mb29iYXI= This value is the one you must input for the Authorization header when using "Try It"

Personal authentication

Authenticate a user by means of email and password.
Only use this endpoint for browser-based integrations, where you want to personally sign the user in.

 
posthttps://api.timekit.io/v2/auth
curl --request POST \
    --url https://api.timekit.io/v2/auth \
    --header 'Content-Type: application/json' \
    --data '{
           "email": "doc.brown@timekit.io",
           "password": "FluxCapacitator"
       }'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "fca27950-1be8-41e2-951c-a43a61d45d43",
    "first_name": "Dr. Emmett",
    "last_name": "Brown",
    "name": "Dr. Emmett Brown",
    "email": "doc.brown@timekit.io",
    "image": "http:\/\/www.gravatar.com\/avatar\/35b00087ea20066e5da95f8359183f04",
    "timezone": "America\/Los_Angeles",
    "api_token": "nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW"
  }
}

Body Params

email
string
required
password
string
required
 

This endpoint is meant for browser-based integrations only.

You should not use this endpoint for server-to-server integrations, because that would mean that you're storing your users passwords, most likely in clear text which you should absolutely not do!
Only use this endpoint when the passwords comes directly from your user!

Use this endpoint at the beginning of your user's session when interacting with Timekit and store the returned api_token in the users session. The API is sessionless so you need to provide the api_token with each subsequent API request as the password part of basic http authentication.
In order for personal authentication to work, you must also supply the "Timekit-App" header, with the value set to the slug of the app the user is requesting through.

So a valid personally authenticated request, using the above api_token, would look like this

curl --request POST \
    --url https://api.timekit.io/v2/findtime \
    --header 'Content-Type: application/json' \
    --header 'Timekit-App: back-to-the-future' \
    --user doc.brown@timekit.io:nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
    --data '{
        "resource_ids": [
            "78a4d873-2a68-41c6-bdd4-c0ca5b35efd3"
        ],					 
            "future": "2 days",
            "length": "4 hours"
        }'
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "https://api.timekit.io/v2/findtime");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.setRequestHeader("Timekit-App", "back-to-the-future");
xmlhttp.setRequestHeader("Authorization", "Basic " + btoa("doc.brown@timekit.io:nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW"));
xmlhttp.send('{"resource_ids": ["78a4d873-2a68-41c6-bdd4-c0ca5b35efd3"],"future": "2 days","length": "4 hours"}');
//see: https://github.com/timekit-io/js-sdk
timekit.configure({
  app: 'back-to-the-future',
  resourceEmail: 'doc.brown@timekit.io',
  resourceKey: 'nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW'
})

Authenticated personally also means that you will have to omit the resource_id parameter otherwise required where relevant. This parameter is to specify which resource should be booked etc, being personally authenticated makes this value redundant and so it should be omitted.

Dynamic includes

 

On most resources, you can dynamically include related objects (aka. expand objects). E.g. for a resource you can include the resource's calendars in the response by adding ?include=calendars to the URL.

You may also supply multiple objects that you want to fetch by separating them with commas, e.g. ?include=calendars,accounts

Available includes will be listed under each endpoint.

Example request with included calendar:

curl --request GET \
  --url https://api.timekit.io/v2/resources/78a4d873-2a68-41c6-bdd4-c0ca5b35efd3?include=calendars \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7

Example response

{
    "data": {
        "activated": true,
        "calendars": [
            {
                "id": "fef0da1b-80d4-46f8-8d38-4457aad38fc1",
                "backgroundcolor": "#FFFFFF",
                "description": "Doc. Browns bookings",
                "foregroundcolor": "#000000",
                "name": "Bookings",
                "system": false
            }
        ],
        "email": "doc.brown@timekit.io",
        "first_name": "Dr. Emmett",
        "img": "http://www.gravatar.com/avatar/7a613e5348d63476276935025",
        "last_name": "Brown",
        "last_sync": null,
        "name": "Dr. Emmett Brown",
        "timezone": "America/Los_Angeles",
        "token": "UZpl3v3PTP1PRwqIrU0DSVpbJkNKl5gN"
    }
}

You can include data in nested layers, so if you include calendars then you can also include events (since events are nested under calendars). You can achieve that by using the dot annotation, so ?include=calendars.events, will return your calendars including their events.

Example request:

curl --request GET \
  --url https://api.timekit.io/v2/resources/78a4d873-2a68-41c6-bdd4-c0ca5b35efd3?include=calendars.events \
  --header 'Content-Type: application/json' \
	--user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7

Will return:

{
    "data": {
        "activated": true,
        "calendars": [
            {
              	"id": "fef0da1b-80d4-46f8-8d38-4457aad38fc1",
                "backgroundcolor": "#FFFFFF",
                "description": "Doc. Browns bookings",
                "events": [
                    {
                      "id": "892d7425-ea2d-4d7d-a74e-e69fad7813cc",
                      "what": "Update",
                      "where": "Skype",
                      "rsvp": "needsAction",
                      "allDay": false,
                      "start": "2014-10-14T14:30:00+00:00",
                      "end": "2014-10-14T15:30:00+00:00",
                      "description": "Update about the FluxCapacitator"
                    },
                    {
                      "id": "4b08a047-3133-41f1-83e1-27cb933d8dbb",
                      "what": "Strategy Meeting",
                      "where": "1355 Market st, San Francisco, CA",
                      "rsvp": "accepted",
                      "allDay": false,
                      "start": "2014-10-14T10:00:00+00:00",
                      "end": "2014-10-14T12:00:00+00:00",
                      "description": "How to make a timemachine"
                    },
                ],
                "foregroundcolor": "#000000",
                "name": "Bookings",
                "system": false
            }
        ],
        "email": "doc.brown@timekit.io",
        "first_name": "Dr. Emmett",
        "img": "http://www.gravatar.com/avatar/7a613e5348d63476276935025",
        "last_name": "Brown",
        "last_sync": null,
        "name": "Dr. Emmett Brown",
        "timezone": "America/Los_Angeles",
        "token": "UZpl3v3PTP1PRwqIrU0DSVpbJkNKl5gN"
    }
}

Responses & errors

 

In general, responses follow common HTTP conventions as much as possible.

Code
Name
Explanation

200

OK

Everything went okay

201

Created

Returned when POSTing to create a new resource was successful

400

Bad Request

The request was malformed (missing parameters throw 422)

401

Unauthorized

Invalid credentials supplied

422

Unprocessable Entity

A POST data JSON key or alike is malformed or missing

500

Internal Server Error

If you encounter this, please get in touch - this should not happen

Successful calls:

Successful requests that result in 200 response codes will have their data inside a key named "data":

// 200 OK
{
  "data": "Response data here"
}

Error messages:

Whenever an error occurs (e.g. validation), the API will attempt to write the error message inside a key named "error":

// 400 Bad Request
{
  "error": {
    "message": "Error message here",
    "status_code": 400
  }
}

If more than one error occurs (e.g. multiple fields fail validation), the key will be named "errors" and the relevant messages will be contained in an array:

// 422 Bad Request
{
  "errors": {
    "first_name": {
      "The first name field is required."
    },
    "email": {
      "The email field is required."
    },
    "timezone": {
      "The timezone field is required."
    }
  }
}

Pagination

 

All listing endpoints in the API are paginated. In each paginated response, information related to the previous and next page of the result set is included.

A ?limit argument can be added to a request, in order to change the number of results on each page.

To retrieve the next page of results, use the query param ?page to specify which page.

Default limit

The default limit is set to 50 for most resources in the API.

Are there more pages?

Use the next_page_url in the response to determine whether there are additional pages to fetch, i.e. only show a "Load more" button if next_page_url is not null.

Example:

curl --request GET \
  --url https://api.timekit.io/v2/bookings?limit=3&page=2 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7

Will return:

{
  "total": 5,
  "per_page": "3",
  "current_page": 2,
  "last_page": 2,
  "next_page_url": null,
  "prev_page_url": "https://api.timekit.io/v2/bookings?limit=3&page=1",
  "from": 4,
  "to": 5,
  "data": [
    {
      "id": "c125d175-132a-499e-8beb-87f31378d5ab",
      "state": "initialized",
      "graph": "instant",
      "completed": false,
      "created_at": "2016-09-15T11:23:09+0300",
      "updated_at": "2016-09-15T11:23:09+0300"
    },
    {
      "id": "06502f41-78b3-4d03-9b6d-4c8b84e360ff",
      "state": "initialized",
      "graph": "instant",
      "completed": false,
      "created_at": "2016-09-15T11:23:09+0300",
      "updated_at": "2016-09-15T11:23:09+0300"
    }
  ]
}

Get current app

Get the app for the authenticated App API-Key

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/app
curl --request GET \
  --url https://api.timekit.io/v2/app \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "9857f6bb-1e79-4a9f-aa59-7385d4e141e2",
    "slug": "back-to-the-future",
    "settings": {
      "name": "Back to the Future",
      "callback": "http:\/\/www.backtothefuture.com\/callback",
      "from_email": "robert.zemeckis@universalpictures.com",
      "from_name": "Robert Zemeckis",
      "contact_name": "Robert Zemeckis",
      "contact_email": "robert.zemeckis@universalpictures.com"
    },
    "created_at": "1985-12-04T12:00:00-0800",
    "updated_at": "2017-11-15T05:40:38-0800",
    "creator_resource_id": "d856b5cf-b06f-46c4-b310-c33612e67768",
    "role": "creator",
    "test_mode": false
  }
}

Query Params

include
string
 

Invite resources to app

Invite existing resources to your app

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/app/invite
curl --request GET \
  --url https://api.timekit.io/v2/app/invite \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
  	"email": "invite-this-email@example.org"
  }'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

email
string

The email you want to invite to your app

 

You can invite an already existing resource by using this endpoint. The resource will receive an email with a link, once the resource clicks the link it will be added to your app.

Resources overview

 

The core of Timekit is bookable resources which can represent everything from people (employees, vendors), to items (screwdriver, musical instrument, vehicles), and locations/venues (meeting rooms). Basically anything that has some available time or needs to be booked in order for your business to succeed.

➡️ Read our tutorial on how to create resources.
➡️ Read our tutorials on how to create Google and Microsoft synced resources.

Create a resource

Create a new resource

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/resources
curl --request POST \
  --url https://api.timekit.io/v2/resources \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
           "email": "doc.brown@timekit.io",
           "timezone": "America/Los_Angeles",
           "name": "Doc Brown",
    			 "password": "FluxCapacitator",
           "tags": [
              "time-travel",
              "doctor",
              "delorean"
           ],
           "image": "https://foo.bar/baz.png"
       }'
{
    "email": "doc.brown@timekit.io",
    "timezone": "America/Los_Angeles",
    "first_name": "Emmet",
    "last_name": "Brown",
    "password": "FluxCapacitator"
}
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
    "first_name": "Doc Brown",
    "last_name": "",
    "name": "Doc Brown",
    "email": "doc.brown@timekit.io",
    "timezone": "America/Los_Angeles",
    "image": "https://foo.bar/baz.png"
  }
}
{
  "errors": {
    "name": [
    	"The name field is required."
    ],
    "timezone": [
    	"The timezone field is required."
    ]
  }
}

Body Params

name
string
required

Set the name of the resource

timezone
string
required

Timezone of the resources

email
string

Email of the resources. Only required if resources need to log in to the Timekit admin (see the blue box below).

first_name
string

First name of the resources, useful if you're creating users as resources

last_name
string

Last name of the resources

password
string

Password of the resources (if not set, a random password will be assigned - can be reset subsequently)

tags
array of strings

If you want to tag a resource. Only "slugs" are valid (lower-case alphanumerics and dashes)

availability_constraints
array

Define resource-level availability constraints to be used by our POST /availability endpoint. Lean more

image
string

Url of an image representing the resource

 

Create resources programmatically.

🔒Only available on Platform plan

Creating resources through the API is locked on the Essential and Professional plans. Please see our pricing page.

Will your resources log into Timekit?

It's possible for the resources you add to Timekit to log in and use the Timekit admin interface to manage their bookings. All you need to do is to provide their email address when you sign them up via the API. You can also provide a password - or they can create one themselves afterwards.

What if I get a "Email already exists" when I create a resource?

You can invite the resource to your app instead, see this endpoint: https://reference.timekit.io/v2/reference#appsinvite

List all resources

Get all resources for the app

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/resources
curl --request GET \
  --url https://api.timekit.io/v2/resources \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
      "first_name": "Emmet",
      "last_name": "Brown",
      "name": "Emmet Brown",
      "email": "doc.brown@timekit.io",
      "timezone": "America/Los_Angeles",
    },
    {
      "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
      "first_name": "Marty",
      "last_name": "McFly",
      "name": "Marty McFly",
      "email": "marty.mcfly@timekit.io",
      "timezone": "America/Los_Angeles",
    }
  ]
}
 

If you need to fetch all resources for your app you can use this endpoint.

Dynamic includes

Available includes:

  • calendars
  • properties
  • tags
  • availability_constraints

Search

Possible search attributes are:

  • tags
  • email

Retrieve a resource

Get a specific resource by ID

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/resources/id
curl --request GET \
  --url https://api.timekit.io/v2/resources/d187d6e0-d6cb-409a-ae60-45a8fd0ec879 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
    "first_name": "Emmet",
    "last_name": "Brown",
    "name": "Emmet Brown",
    "email": "doc.brown@timekit.io",
    "image": "http://www.link-to-img.com/image.png",
    "timezone": "America/Los_Angeles",
  }
}

Path Params

id
string
required

Id of the specific resource

 

Update a resource

Update a specific resource

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/resources/id
curl --request PUT \
  --url https://api.timekit.io/v2/resources/d187d6e0-d6cb-409a-ae60-45a8fd0ec879 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
          "first_name": "Emmet",
          "last_name": "Brown",
          "password": "FluxCapacitor",
          "timezone": "America/Los_angeles"
        }'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
    "first_name": "Emmet",
    "last_name": "Brown",
    "name": "Emmet Brown",
    "email": "doc.brown@timekit.io",
    "timezone": "America/Los_Angeles",
  }
}

Path Params

id
string
required

id of the specific resource

Body Params

first_name
string

First name of the user

last_name
string

Last name of the user

timezone
string

User's timezone following "area/city" schema

password
string

User's password in cleartext

tags
array of strings

If you want to tag a resource. Only "slugs" are valid (lower-case alphanumerics and dashes)

 

Update the current user's/resource's properties like name, password and timezone.

Email is immutable

Resource e-mail cannot be changed once created. Please create a new resource if you would like to use another email.

Google and timezone

Note that if you have a Google account connecting and are attempting to update the timezone, it will be overridden by the timezone specified in Google calendar. Therefore, change the timezone in Google calendar instead.

Delete a resource

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.timekit.io/v2/resources/id
curl --request DELETE \
  --url https://api.timekit.io/v2/resources/d187d6e0-d6cb-409a-ae60-45a8fd0ec879 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required
 

Availability constraints

Set availability-constraints for a single resource in order to limit availability. A common use-case is to set an employees working hours, especially if these are different than a company's opening hours. Another common use-case is setting up vacation which are also employee-specific and not business-specific.

 

A resource's availability constraints are set by providing the availability_constraints parameter when creating or updating a resource. The most common use-case is Opening Hours that specifies when a given resource is available (globally, no matter which project they are added to).

Here's how a request would look like:

curl --request PUT \
  --url https://api.timekit.io/v2/resources/d187d6e0-d6cb-409a-ae60-45a8fd0ec879 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
      "availability_constraints": [
      	{ "allow_day_and_time": {"day": "Monday", "start": 9, "end": 12 }},
      	{ "allow_day_and_time": {"day": "Monday", "start": 14, "end": 17 }},
      	{ "allow_day_and_time": {"day": "Tuesday", "start": 9, "end": 17 }},
      ]
    }'

This will make the resource available only on Mondays and Tuesdays. These constraints will be combined with any provided constraints passed to the POST /availability endpoint when calculating availability for the resource.

Please refer to our availability constraints section for more on the topic

Availability overview

 

A central feature of Timekit is searching for availability of your resources. Availability is timeslots that
your resources are open for booking i.e. spots where they are not already booked or blocked.

We support different modes/types of availability: round-robin and mutual, you can retrieve availability for a single resource or multiple at the same time.
Constraints are used to further limit the search space, with the most common use case being opening hours.

Using the old /findtime endpoint?

This endpoint is the successor to our POST /findtime endpoint and has been redesigned for speed and more flexibility. It supports our new Projects model.
Read our migration guide.
You can also read the old reference here.

Query availability

Query for availability of resources

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/availability
curl --request POST \
  --url https://api.timekit.io/v2/availability \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
           "project_id": "68b7m193-2a68-41c6-bdd4-c0ca5b35ops5",
         }'
curl --request POST \
  --url https://api.timekit.io/v2/availability \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
           "mode": "roundrobin_random",
           "resources": [
             "78a4d873-2a68-41c6-bdd4-c0ca5b35efd3"
           ],					 
           "length": "4 hours",
           "from": "3 days",
           "to": "4 weeks",
           "buffer": "30 minutes",
           "ignore_all_day_events": true
         }'
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "start": "2018-12-07T00:00:00+01:00",
      "end": "2018-12-07T04:00:00+01:00",
      "resources": [
        {
          "id": "22e8c963-2a13-4809-9601-dee0129a5aca",
          "name": "Marty McFly",
          "timezone": "Europe\/Stockholm"
        }
      ]
    },
    {
      "start": "2018-12-07T04:00:00+01:00",
      "end": "2018-12-07T08:00:00+01:00",
      "resources": [
        {
          "id": "22e8c963-2a13-4809-9601-dee0129a5aca",
          "name": "Marty McFly",
          "timezone": "Europe\/Stockholm"
        }
      ]
    },
    {
      "start": "2018-12-07T08:00:00+01:00",
      "end": "2018-12-07T12:00:00+01:00",
      "resources": [
        {
          "id": "22e8c963-2a13-4809-9601-dee0129a5aca",
          "name": "Marty McFly",
          "timezone": "Europe\/Stockholm"
        }
      ]
    }
  ]
}
{
  "errors": {
    "query": [
      "The query field is required."
    ]
  }
}

Body Params

project_id
string

If you're using our projects model, specify the project ID and all parameters to the endpoint will be retrieved dynamically from the project. Any additional parameters in the request are not required and will override those set in the project.

mode
string

Specify the type of availability you want calculated and returned, valid modes are: "mutual", "roundrobin_random", "roundrobin_prioritized"

resources
array of strings

Array of resource IDs that should be included in the availability search

constraints
array

Array of constraint objects that either whitelist or blacklist timespans. These constraints are dynamically applied for each resource. Please ready about constraints for reference

length
string

How long each available time-slot should be. "Null" simply returns timeslots in dynamic intervals without a fixed length.

from
string

Defines the beginning of the search-space written is human language, eg. "1 day", "2 weeks" or "tomorrow"

to
string

Defines the end of the search-space written is human language, eg. "1 day", "2 weeks" or "tomorrow" (max 6 months)

buffer
string

The amount of buffer time you want to pad around existing events (see note)

ignore_all_day_events
boolean

DEPRECATED see below. Set to true if all day events in your calendars NOT should be counted as blocked/unbookable

output_timezone
string

If you want the outputted time-slots to be formatted to a particular timezone, set it with this parameter. Please note that this parameter will not affect the resource-relative timezones of the constraints. Please see our constraints section for further information.

timeslot_increments
string

Define at which time increments the time-slots should start. Please se the note

 

Fetch availability of your resources in the form of timeslots. The availability engine is quite flexible and allows you to handle complex use-cases with different constraints across many resources.

Available until blocked

The default notion in Timekit is that a resource is available until blocked. Blocked meaning that an event is reserving time in the calendar (through provider sync or existing bookings) or that some general business rules like opening hours have been applied (as constraints).

If you on the other hand want to predefine available timeslots in advance, please refer to the availability section in the docs.

Project ID

With our project model, you can predefine which parameters are used to query availability. If your integration with Timekit is based on projects, simply use the ID of the project instead of setting the parameters directly in the call.
Please refer to our Projects overview.

Mode

When calculating availability for one or more resources, you need to choose a strategy for how you want timeslots returned. This is specified by the mode parameter, which have the following options:

Round-robin random
roundrobin_random is used when you want any of the specified resources to be available. It shuffles the resources array, then calculates each resource's availability and finally returns a list of timeslots with a single bookable resource per timeslot. The returned resource for a given timeslot is random based on the initial shuffle of the list of bookable resources. This can be used when you have a pool of resources, e.g. a team of salespeople, but you only need to book one of them.

Round-robin prioritized
roundrobin_prioritized is same as above, but will respect the order of the resources you supply in the resources array and favor the first one if multiple resources are availability at a given time.

Mutual
mutual searches for overlapping timeslots where all of the specified resources need to be available. Ideal for use-cases like meetings with multiple participants or rooms that require equipment to be accessible.
Note that there can only be one resource that is "owning" the created booking, so if you need to include more resources in the booking, make sure to add them as participants to the final event to make sure their calendar is blocked too.

Constraints

At the heart of the availability engine is what we call "constraints": business rules that reduces the available ranges of time that a given resource can be available. In the most common use-cases, these are exemplified as opening hours e.g. a resource should only be a available certain days (monday-tuesday) and at certain times (1pm-5pm).

The constraints that you specify in the constraints parameter are applied dynamically to each resource in the resources array. This is in addition to the constraints that you might have defined on the globally on resource model outside of the POST /availability request, see POST /resources for how to set a resource's availability.

We do not check for logical blockage on constraints in relation to the search space, this is up to you to check for. For example if your search space consists of just two days, e.i. "from":"now", "to":"2 days" and use the constraint "block_weekends" and you request the endpoint on a saturday morning, you will get no results and you will get no errors or warnings.

How availability is calculated

In essence, the availability engine converts all constraints, calendar events and bookings into "blocking timeslots" that is subtracted from the final output of available timeslots.

For each resource, these are calculated in the following order:

1) Parameters from and to supplied in the request (or defined in a project)
2) Global constraints supplied in the request (or defined in a project)
3) Resource-level constraints saved on the resource model
4) Bookings owned by the resource
5) Calendar events for the resource (synced through Google/Microsoft)

Buffer Time

The buffer option makes sure that you have some breathing time between any existing events in your calendars, and the available time-slots offered. Once an available time-slot has been booked and turned into a calendar event, additional buffer time will be added to it, when querying for availability.

You define buffer like you define length: "15 minutes", "1 hour" etc.

Timeslot increments

By default, the algorithm will return sequential time-slots. The time-slots will not overlap, which means that some potential time-slots are ignored. If you want overlapping time-slots you define the increment from the previous time-slot start with this setting.

Example without timeslot_increments:

If we request time-slots of 1 hours length, from 10 to 12, without timeslot_increments defined, these 2 time-slots will be returned:
10:00-11:00
11:00-12:00

Examples with timeslot_increments:

If we request with timeslot_increments: "15 minutes", these 5 time-slots will be returned:
10:00-11:00
10:15-11:15
10:30-11:30
10:45-11:45
11:00-12:00

If we request with timeslot_increments: "30 minutes", these 3 time-slots will be returned:
10:00-11:00
10:30-11:30
11:00-12:00

Deprecated ignore_all_day_events

With the release of available events, the setting ignore_all_day_events has been deprecated. By default an all day event in google calendar is an available event and will as such not block availability.
If you create all_day_events manually through the /events endpoint, you need to make sure to also set the "available" parameter to true in order to make sure that the event isn't blocking.

Constraints

Use constraints to set general rules for availability.

 

Formerly known as "filters"

In our previous availability endpoint POST /findtime, constraints were known as "filters". We've renamed them to "constraints", but they serve the same purpose.

The most typical use-case for constraints is setting opening hours and/or working hours. You can do this with two different kinds of constraints; blocking and allowing. "Allowing" constraints implicitly blocks everything else, so for instance the constraint AllowDay, with the day set to monday, will block all the other days in the week. This means that you do not need to explicitly block periods that are implicitly being blocked with an "allowing" constraint. So if you are using the allow_weekdays constraint, you don't need to also supply the block_weekends constraint.

You can combine constraints to fit your use-case. As mentioned the most common use case is setting opening hours. With opening hours Monday to Friday 9am to 5pm this would look like this:

"constraints": [
  {"block_weekends": {} },
  {"allow_hours": {"start": 9, "end": 17} }
]

If you are closed for an hour during lunch, you could add a "blocking" contstraint:

"constraints": [
  {"block_weekends": {} },
  {"allow_hours": {"start": 9, "end": 17} },
  {"block_hours": {"start": 12, "end": 13} }
]

You can set constraints for your resources (eg. individual working hours in their specific timezone) and your projects (eg. business opening hours). You can also add constraints on the fly when you perform your availability queries. All of these different constraints will be taken into account by Timekit when looking for availability.

Available constraints

Day and time

Allow or block certain hours on a specific day of the week.

// Allow Mondays from 9am-5pm
"constraints": [
  {"allow_day_and_time": {"day": "Monday", "start": 9, "end": 17} },
]

// Block the day and time instead
"constraints": [
  {"block_day_and_time": {"day": "Monday", "start": 9, "end": 17} },
]

Hours

Allow or block certain hours of the day.

// Opening hours with lunch break
"constraints": [
  {"allow_hours": {"start": 9, "end": 17} },
  {"block_hours": {"start": 12, "end": 13} }
]

Day

Allow or block a specific day.

// Allow Mondays
"constraints": [
  {"allow_day": {"day": "Monday"} },
]

// Block the day instead
"constraints": [
  {"block_day": {"day": "Monday"} },
]

Period

Allow or block a specific time period given two timestamps.
Ideal for blocking out a fixed timerange like holidays (if it's not practical to block out the time using calendar events instead)

// Allow from June 1st 9am to June 30th 5pm
"constraints": [
  {"allow_period": {"start": "2018-06-01 09:00:00", "end": "2018-06-30 2018-06-30 17:00:00"} }
]

Weekends

Only allow or block weekends.

"constraints": [
  {"allow_weekends": {} }
]

"constraints": [
  {"block_weekends": {} }
]

Broad availability query

Get a list of resources that have at least one available time-slot.

Use this endpoint when you have many resources and need a quick answer to which one of them has some availability and you don't need to know their exact available time-slots.

Please note that this is an add-on feature that we need to enable before you can use it. Please contact yourfriends@timekit.io for more info.

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/availability/resources
curl --request GET \
  --url https://api.timekit.io/v2/availability/resources \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
  --data '{
    "resources": ["2cd3f391-e2d7-4af5-aed3-7d752583fa68","1bd77c4e-1d27-4cc8-87df-258122b62f1f","aef7ebc7-b94c-4d0c-825f-970e8b13b3a4","630071c3-9450-48d1-9b59-2d25aaa9441f","e6cef9a8-7326-4a6e-b085-4b58efc92f66"],
    "from": "2018-06-017T00:00:00+01:00",
    "to": "2018-07-017T00:00:00+01:00",
    "length": "1 hour",
    "limit": 2
  }'
A binary file was returned

You couldn't be authenticated

{data:["2cd3f391-e2d7-4af5-aed3-7d752583fa68","1bd77c4e-1d27-4cc8-87df-258122b62f1f"]}

Body Params

resources
array of strings
required

Which resources to query, an array of IDs

from
date
required

Defines the beginning of time-space to search in. Must be in the future.

to
date
required

Defines the end of time-space to search in. Must be within 6 months.

length
string
required

The length of the availability.

limit
int32

How many resource id's should at most be returned. If not set all available resources will be returned

 

As you can see from the example above, this endpoint does not return availability, but just which resources have some availability that fits the length within the time-space defined by from and to.

This is endpoint useful when you have many resources and want to filter by relevant ones and querying the /availability endpoint takes too long.

Bookings overview

 

At the core of Timekit are bookings. In the following sections you will learn about how to manage your bookings via the API.

Learn more

If you want to learn more about bookings, have a look in our Help Center.

Group bookings

If you are working with group bookings or classes, have a look at our group bookings guide.

Webhooks

You can use webhooks to customize Timekit and integrate it into your existing workflows and systems.

If you are building something with webhooks, have a look at our introduction to webhooks.

Create a booking

Use this endpoint to create a booking.

Please refer to our tutorial on creating a booking for a more detailed description: http://help.timekit.io/working-with-the-api/bookings/creating-a-booking

If you need an introduction the the booking concept as Timekit sees it, please refer to our introduction: http://help.timekit.io/working-with-the-api/bookings/introduction-to-bookings

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/bookings
curl --request POST \
  --header 'Content-Type: application/json' \
  --url https://api.timekit.io/v2/bookings \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
  "resource_id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
  "graph": "confirm_decline",
  "start": "2018-08-12T21:30:00-07:00",
  "end": "2018-08-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!",
  "meta":{
    "latitude":"34.1381168",
    "longitude":"-118.3533783"
  }
  "customer": {
    "name": "Marty McFly",
    "email": "marty.mcfly@timekit.io",
    "phone": "(916) 555-4385",
    "voip": "McFly",
    "timezone": "America/Los_Angeles"
  }
}'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "graph": "confirm_decline",
    "state": "tentative",
    "completed": false,
    "created_at": "2018-02-11T11:58:45+0100",
    "updated_at": "2018-02-11T11:58:47+0100",
    "available_actions": [
      "decline",
      "confirm"
    ],
    "attributes": {
      "event_info": {
        "start": "2018-08-12T21:30:00-07:00",
        "end": "2018-08-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!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}

Query Params

includes
string

Include booking attributes such as event_info in the response

Body Params

project_id
string

If you want to use the settings specified in the project. Any additional parameters in the request will override those set in the project

resource_id
string
required

The ID of the resource being booked

graph
string
required

Name of the flow graph you want to use. Please refer to our graph reference https://reference.timekit.io/reference#graphs

customer
object
required

Customer info (dependending on the chosen graph!) the customer is the person booking the resource.

 
customer.name
string
required
customer.email
string
required
customer.phone
string
customer.voip
string
customer.timezone
string
start
date-time
required

When the booking starts

end
date-time
required

When the booking ends

what
string
required

The title of the booking

where
string
required

A description of the location of the booking

description
string
required

a description of the booking

invite
boolean

Send provider invitation emails when using google/microsoft. See details under event.

participants
array of strings

A list of emails to invite as participants (when using google/microsoft). See details under event.

my_rsvp
string

Set your own RSVP when using google/microsoft. See details under event.

calendar_id
string

If you need to save the booking in a different calendar than the resource's primary, you need to supply this

settings
object

Additional settings. See below

 
meta
object

Key-values of additional custom meta-data that you want to save.

 
 

Settings

Use the settings for additional settings. Currently we support these additional settings:

  • allow_double_bookings which defaults to false. If you want bookings to allow overlapping you can set this to true
{
  "resource_id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
  "graph": "confirm_decline",
  "start": "2018-08-12T21:30:00-07:00",
  "end": "2018-08-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": "marty.mcfly@timekit.io",
    "phone": "(916) 555-4385",
    "voip": "McFly",
    "timezone": "America/Los_Angeles"
  },
  "settings": {
    "allow_double_bookings": false
  }
}

List all bookings

Use this endpoint to get all bookings

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/bookings
curl --request GET \
  --url https://api.timekit.io/v2/bookings?include=available_actions,attributes,calendar,customers \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 
  
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
      "state": "confirmed",
      "graph": "confirm_decline",
      "completed": true,
      "created_at": "2016-02-11T12:39:45+0100",
      "updated_at": "2016-02-11T13:12:01+0100",
      "available_actions": [],
      "attributes": {
        "event_info": {
          "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!"
        }
      },
      "calendar": {
        "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
        "name": "Important encounters with Marty",
        "display_name": "Important encounters with Marty",
        "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
        "foregroundcolor": "#000000",
        "backgroundcolor": "#FFFFFF",
        "created_at": "2016-02-15T13:21:42+0100",
        "updated_at": "2016-02-15T13:21:42+0100"
      },
      "customers": [
        {
          "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
          "name": "Marty McFly",
          "email": "marty.mcfly@timekit.io",
          "phone": "(916) 555-4385",
          "voip": "McFly",
          "timezone": "America/Los_Angeles"
        }
      ]
    },
	  {
      "id": "f68979ff-27da-4afd-8d0c-847f9340331b",
      "state": "tentative",
      "graph": "confirm_decline",
      "completed": false,
      "created_at": "2016-02-11T12:39:45+0100",
      "updated_at": "2016-02-11T13:12:01+0100",
      "available_actions": [
      	"confirm",
        "decline"
      ],
      "attributes": {
        "event_info": {
          "start": "1955-11-05T09:30:00-07:00",
          "end": "1955-11-05T09:45:00-07:00",
          "what": "Deliver the Pacard to the auto shop",
          "where": "Western Auto Store, Hill Valley, CA 95420, USA",
          "description": "The clutch needs tightening"
        }
      },
      "calendar": {
        "id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
        "name": "My personal calendar",
        "display_name": "My personal calendar",
        "description": "Notes to self, so I don't remember to to them.",
        "foregroundcolor": "#25d6be",
        "backgroundcolor": "#ea1cb8",
        "created_at": "2016-02-15T13:21:42+0100",
        "updated_at": "2016-02-15T13:21:42+0100"
      },
      "customers": [
        {
          "id": "78a4d873-2a68-41c6-bdd4-c0ca5b35efd3",
          "name": "Dr. Emmett Brown",
          "email": "doc.brown@timekit.io",
          "phone": "(916) 555-4385",
          "voip": "DocBrown",
          "timezone": "America/Los_Angeles"
        }
      ]
    }
  ]
}

Query Params

limit
int32

Pagination limit intervals (X means first X is returned)

page
int32

Which pagination interval to retrieve (set limit for interval size)

search
string

Add 1 or more search criteria to your query. Please see our search reference: https://reference.timekit.io/reference#search

include
string

Dynamic includes

orderBy
string

Order bookings by one of the following attributes: created_at, updated_at, event.start, event.end, completed, graph, state

sortedBy
string

Used together with orderBy to determine the direction of the sorting. Can be set to either asc or desc.

start
date

Filter bookings by when they start, must be accompanied by end.

end
date

Filter bookings by when they end, must be accompanied by start.

 

Search

Possible search attributes are:

  • resource.id
  • graph
  • state
  • completed (true/false)
  • customer.name (including wildcards)
  • customer.email
  • customer.<customer field name>
  • calendar.id
  • project.id
  • meta.*

Regarding meta you can search on key-value pairs like this: meta.[key]:[value], A complete example searching for the meta-key=foo and the value=bar: https://api.timekit.io/v2/bookings?search=meta.foo:bar

Regarding wildcards on customer.name, the wildcard is * and you can pre- and suffix the search string with the wildcard. For example if you want to search for all names beginning with Marty (for instance if you don't know that his last name is McFly) you would search by suffixing Marty with the wildcard like so: search=customer.name:marty* Also note that the customer.name search is case-insensitive.

The elements in the returned JSON is dependent on the graph and state of the booking.

Dynamic includes

In addition to the basic booking data, you can fetch the following booking-related data:

Example:
https://api.timekit.io/v2/bookings?include=logs,attributes,customers,calendar,event

Retrieve a booking

Use this endpoint to get a specific booking

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/bookings/id
curl --request GET \
  --url https://api.timekit.io/v2/bookings/58190fc6-1ec0-4ebb-b627-7ce6aa9fc703 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "state": "confirmed",
    "graph": "confirm_decline",
    "completed": true,
    "created_at": "2016-02-11T12:39:45+0100",
    "updated_at": "2016-02-11T13:12:01+0100",
    "available_actions": [],
    "attributes": {
      "event_info": {
        "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!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}
{
  "error": "Resource does not exist",
  "model": "Timekit\Booking"
}

Path Params

id
string
required

The id of the booking

Query Params

include
string

Dynamic includes

 

For dynamic includes, see /bookings

Update booking state

Perform an action on a booking to update its state.

For a tutorial on how to perform the "confirm" action, head on over to our help center: http://help.timekit.io/working-with-the-api/bookings/confirming-bookings

Please also check out our Action links article on how you can create one-time links that will be safe to share with your customers, like links in an email. Use this for your customers to confirm, cancel or perform any other action on a booking without involving your backend.

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/bookings/id/action
curl --request PUT \
  --url https://api.timekit.io/v2/bookings/58190fc6-1ec0-4ebb-b627-7ce6aa9fc703/confirm \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{}'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "graph": "confirm_decline",
    "state": "confirmed",
    "completed": false,
    "created_at": "2016-02-11T11:58:45+0100",
    "updated_at": "2016-02-11T11:58:47+0100",
    "available_actions": [
      "decline",
      "confirm"
    ],
    "attributes": {
      "event_info": {
        "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!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}

Path Params

id
string
required

The ID of the booking

action
string
required

Which action to trigger

Body Params

apply_to_bulked_bookings
boolean

If the booking is bulked and related, the action will be replicated to the other bulked bookings, this parameter can disable this default behaviour. Please see https://reference.timekit.io/reference#bookingsbulk

 

Changing the state of a booking is done via actions. Some actions will autoplay and some can be manually triggered via this endpoint.

The actions available for a given booking are dependent on which graph the booking follows and which state the booking is in.

Some actions can take inputs/settings. For example, in the confirm_decline graph, the decline action can take a message and be enabled/disabled. Please see the reference for the relevant graph to see which inputs are valid.

If the action you're performing results in a final state where the booking cannot take other actions (e.g. completed, paid, declined etc), the response will have a completed key set to true.

Common actions

Confirm a booking: use the action confirm

Decline a booking: use the action decline

Cancel a booking: use the action cancel (if the resource cancels) or cancel_by_customer (if its the customer that initiates the cancellation)

Update booking meta data

Update meta data related to a given booking.

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/bookings/id/
curl --request PUT \
  --url https://api.timekit.io/v2/bookings/58190fc6-1ec0-4ebb-b627-7ce6aa9fc703 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
  	"meta": {
    	"external_id": "random-id-1234"
    }
  }'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "graph": "confirm_decline",
    "state": "confirmed",
    "completed": false,
    "created_at": "2016-02-11T11:58:45+0100",
    "updated_at": "2016-02-11T11:58:47+0100",
    "available_actions": [
      "decline",
      "confirm"
    ],
    "attributes": {
      "event_info": {
        "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!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}

Path Params

id
string
required

The ID of the booking

Body Params

meta
object

Key-values of additional custom meta-data that you want to save.

 
 

If you have added any meta data to a booking and during the lifespan of a booking you need to update any of there meta data you can use this endpoint.

You remove any meta data by setting it to null, like this:

{
    "meta":{
        "external_id": null
    }
}

List all group bookings

Return all available (tentative) group bookings

For a complete tutorial on working with group bookings, head on over to our help center: http://help.timekit.io/working-with-the-api/bookings/group-bookings

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/bookings/groups
curl --request GET
  --url https://api.timekit.io/v2/bookings/groups \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "id": "0dad9c8f-2801-4b6f-b898-7c69063bed0d",
      "state": "tentative",
      "graph": "group_owner",
      "completed": false,
      "created_at": "2016-02-11T12:39:45+0100",
      "updated_at": "2016-02-11T13:12:01+0100",
      "attributes": {
        "group_booking": {
          "max_seats": 20,
          "current_seats": 0
        },
        "event_info": {
          "start": "2016-09-30T08:00:00+00:00",
          "end": "2016-09-30T09:00:00+00:00",
          "what": "Doc Brown's 1st lecture on flux capacitance",
          "where": "Hill Valley High School, CA 95420, USA",
          "calendar_id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
          "description": "Please arrive 10 minutes before the lecture begins"
        }
      }
    },
    {
      "id": "a1ebdd9d-db42-4cd3-a915-0202a034284a",
      "state": "tentative",
      "graph": "group_owner",
      "completed": false,
      "created_at": "2016-02-11T12:39:45+0100",
      "updated_at": "2016-02-11T13:12:01+0100",
      "attributes": {
        "group_booking": {
          "max_seats": 20,
          "current_seats": 0
        },
        "event_info": {
          "start": "2016-10-06T08:00:00+00:00",
          "end": "2016-10-06T09:00:00+00:00",
          "what": "Doc Brown's 2nd lecture on flux capacitance",
          "where": "Hill Valley High School, CA 95420, USA",
          "calendar_id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
          "description": "Please arrive 10 minutes before the lecture begins"
        }
      }
    }
  ]
}

Query Params

limit
int32

Pagination limit intervals (X means first X is returned)

page
int32

Which pagination interval to retrieve (set limit for interval size)

search
string

Add 1 or more search criteria to your query. See the possibilities under the /bookings endpoint: https://reference.timekit.io/reference#bookings

 

When you want to publicly list all available group bookings for customers to sign up for, you should use this endpoint. It will only include information about the owner event itself and doesn't include sensitive information about customers etc.

Dynamic includes

For security reasons, you can't dynamically include related resources on this endpoint, like with the regular /bookings endpoints.

Retrieve a group booking

Get a specific group booking

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/bookings/groups/:id
curl --request GET
  --url https://api.timekit.io/v2/bookings/groups/0dad9c8f-2801-4b6f-b898-7c69063bed0d \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7     
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "0dad9c8f-2801-4b6f-b898-7c69063bed0d",
    "state": "tentative",
    "graph": "group_owner",
    "completed": false,
    "created_at": "2016-02-11T12:39:45+0100",
    "updated_at": "2016-02-11T13:12:01+0100",
    "attributes": {
        "group_booking": {
          "max_seats": 20,
          "current_seats": 0
        },
        "event_info": {
          "start": "2016-09-30T08:00:00+00:00",
          "end": "2016-09-30T09:00:00+00:00",
          "what": "Doc Brown's 1st lecture on flux capacitance",
          "where": "Hill Valley High School, CA 95420, USA",
          "calendar_id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
          "description": "Please arrive 10 minutes before the lecture begins"
        }
      }
  }
}

Path Params

:id
string
required

ID of the booking

 

When you want to get information about a group booking, you should use this endpoint. It only includes information about the owner event itself, and doesn't include sensitive information about customers etc.

Dynamic includes

For security reasons, you can't dynamically include related resources on this endpoint, like with the regular /bookings endpoints.

Create bookings in bulk

Use this endpoint to create bookings in bulk

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/bookings/bulk
curl -X POST \
  -u :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  -d '{
    "bookings": [
        {
            "graph": "confirm_decline",           
            "resource_id": "2f9cca48-1b78-4ea4-8626-9934c984a6a4",
            "start": "2018-08-20T12:49:58+01:00",
            "end": "2018-08-20T13:49:58+01:00",
            "what": "Doloremque earum ut illum et incidunt aut.",
            "where": "8195 Koss Garden Apt. 873",
            "description": "Nesciunt culpa tempora illum et laborum vel vel.",            
            "action": "create",
            "customer": {
                "name": "Dr. Arlene Lebsack Sr.",
                "email": "umosciski@gmail.com",
                "timezone": "Atlantic\/Cape_Verde"
            },
            "webhooks" : {
                "created": {
                    "enabled": false,
                },
                "confirmed": {
                    "enabled": false,
                }
            },

        },
        {
            "graph": "confirm_decline",            
            "resource_id": "2f9cca48-1b78-4ea4-8626-9934c984a6a4",
            "start": "2018-08-21T12:49:58+01:00",
            "end": "2018-08-21T13:49:58+01:00",
            "what": "Doloremque earum ut illum et incidunt aut.",
            "where": "8195 Koss Garden Apt. 873",
            "description": "Nesciunt culpa tempora illum et laborum vel vel.",            
            "action": "create",
            "customer": {
                "name": "Dr. Arlene Lebsack Sr.",
                "email": "umosciski@gmail.com",
                "timezone": "Atlantic\/Cape_Verde"
            },
            "webhooks" : {
                "created": {
                    "enabled": false,
                },
                "confirmed": {
                    "enabled": false,
                }
            },
        },
        {
            "graph": "confirm_decline",            
            "resource_id": "2f9cca48-1b78-4ea4-8626-9934c984a6a4",
            "start": "2018-08-22T12:49:58+01:00",
            "end": "2018-08-22T13:49:58+01:00",
            "what": "Doloremque earum ut illum et incidunt aut.",
            "where": "8195 Koss Garden Apt. 873",
            "description": "Nesciunt culpa tempora illum et laborum vel vel.",
            "customer": {
                "name": "Dr. Arlene Lebsack Sr.",
                "email": "umosciski@gmail.com",
                "timezone": "Atlantic\/Cape_Verde"
            },
            "action": "create"
        }
    ],
    "delete_all_on_error": true,
    "stop_on_first_error": true
}' \
https://api.timekit.io/v2/bookings/bulk
A binary file was returned

You couldn't be authenticated

{
    
    "data": [
        {
            "id": "b7dd8206-4849-4454-ac4f-fc361bc751f0",
            "state": "tentative",
            "graph": "confirm_decline",
            "completed": false,
            "created_at": "2017-10-20 16:01:07",
            "updated_at": "2017-10-20 16:01:08"
        },
        {
            "id": "3d2f3a37-ff69-4dd1-bbdb-1bfa5fc96d4f",
            "state": "tentative",
            "graph": "confirm_decline",
            "completed": false,
            "created_at": "2017-10-20 16:01:08",
            "updated_at": "2017-10-20 16:01:08"
        },
        {
            "id": "c7b69629-5467-4121-a82d-e9e1c8acb956",
            "state": "tentative",
            "graph": "confirm_decline",
            "completed": false,
            "created_at": "2017-10-20 16:01:08",
            "updated_at": "2017-10-20 16:01:08"
        }
    ]
}

Body Params

bookings
array
required
delete_all_on_error
boolean

If true all booking in the request will be deleted if an error occurs

stop_on_first_error
boolean

If set to true execution will stop on the first error

relate_bookings
boolean

Create relation between the bulked bookings.

 

The two parameters delete_all_on_error and stop_on_first_error can be used to achieve transaction-like behavior. If a booking in your solution consists of multiple bookings in Timekit terms, it may be important that all Timekit bookings are in sync with your booking.

The webhooks settings are to override the default webhooks set on app-level. There should be a corresponding webhooks.[X].enabled=false settings for any app-level webhooks that you want disabled, in order to only get one webhook triggered for a bulk transaction. Notice that the disabling of the webhook is present on all but one of the bookings since you will probably still want to be notified at least once on updates to your booking.
You should probably always disable all webhooks except on the last booking because if the first booking has no error and the next has (at some subsequent state e.g. ‘cancel’), the webhook might still get triggered even though we reset the state.

Related bulked bookings

If you set the relate_bookings parameter to true, you can retrieve all related bookings by retrieving any one of the bulked bookings and dynamically include bulked_bookings like so:
http://api.timekit.io/v2/bookings/{:id}?include=bulked_bookings

Please note that applying an action to a related bulked booking, will automatically replicate to the related bookings as well. So if you "confirm" one of three bulked and related bookings, all three bookings will be "confirmed". This default behaviour can be disabled by adding the body parameter apply_to_bulked_bookings: false

Update bookings in bulk

Bulk update bookings

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/bookings/bulk
curl -X PUT \
  -u :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  -d '{
    "bookings": [
        {
            "id": "b7dd8206-4849-4454-ac4f-fc361bc751f0",            
            "action": "confirm"
        },
        {
            "id": "3d2f3a37-ff69-4dd1-bbdb-1bfa5fc96d4f",            
            "action": "confirm"
        },
        {
            "id": "c7b69629-5467-4121-a82d-e9e1c8acb956",           
            "action": "confirm"
        }
    ],
    "reset_all_on_error": true,
    "stop_on_first_error": false
}' \
https://api.timekit.io/v2/bookings/bulk
A binary file was returned

You couldn't be authenticated

{
    
    "data": [
        {
            "id": "b7dd8206-4849-4454-ac4f-fc361bc751f0",
            "state": "confirmed",
            "graph": "confirm_decline",
            "completed": false,
            "created_at": "2017-10-20 16:01:07",
            "updated_at": "2017-10-20 16:01:08"
        },
        {
            "id": "3d2f3a37-ff69-4dd1-bbdb-1bfa5fc96d4f",
            "state": "confirmed",
            "graph": "confirm_decline",
            "completed": false,
            "created_at": "2017-10-20 16:01:08",
            "updated_at": "2017-10-20 16:01:08"
        },
        {
            "id": "c7b69629-5467-4121-a82d-e9e1c8acb956",
            "state": "confirmed",
            "graph": "confirm_decline",
            "completed": false,
            "created_at": "2017-10-20 16:01:08",
            "updated_at": "2017-10-20 16:01:08"
        }
    ]
}

Body Params

bookings
array
required
stop_on_first_error
boolean
reset_all_on_error
boolean
 

As with bulk creation, reset_all_on_error and stop_on_first_error are in order to get the transaction-like behavior. reset_all_on_error will reset all bookings in the request to the previous state if an error occurs.

Delete a booking

Delete a booking. Please note that only bookings in a final state can be deleted.
Final states are typically 'completed', 'declined' or 'cancelled'. We have this limit in order to make sure that all parties are notified as expected, before we delete the booking. So that no customer shows up to a booking that was deleted without being cancelled first.

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.timekit.io/v2/bookings/id
curl --request DELETE \
  --header 'Content-Type: application/json' \
  --url https://api.timekit.io/v2/bookings/6c3ebfa0-0519-407c-b7bf-7f87214bf2b6 \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
A binary file was returned

You couldn't be authenticated

Try the API to see results
 

Reminders

Setup reminders to send emails or trigger webhooks before or after a booking takes place.

 

This article will give you an overview of how to configure reminders on Timekit.
You can choose to setup reminders on app-level, project-level or simply directly when creating a booking.

Timekit currently operates with two types of reminders: emails and webhooks.

Email reminders

The easiest way to send reminder emails before or after a booking is to use the built-in reminder emails. If you prefer using your own emails, jump to the next section where we talk about using webhooks to achieve the same result.

The emails will look like this in the recipients inbox:

email example

Setting up an email-reminder to be send to the owner 15 minutes before a booking takes place looks like this:

{
  "type": "email",
  "settings": { 
    "recipient": "owner", 
    "subject": "Sales call in 15 mins!"
  },
  "when": {
    "type": "before", 
    "unit": "mins", 
    "time": 15
  }
}

Valid values for recipient are "owner" (the resource being booked) or "customer" (the person/email booking the resource).
Valid values for when.type are "before" (the booking begins) and "after" (the booking begins).
Valid values for when.unit are "secs", "mins" and "hours"

Webhook reminders

In addition to emails, you can also set up webhook reminders that will be triggered either before or after the booking begins. This is useful if you want to send your own emails, and just want to know when to send them.

Webhooks can be used for many other things than just reminders. Maybe you want to send out a questionnaire to your customers a day after the booking?

Setting up a webhook-reminder to be executed one hour after the booking starts looks like this:

{
	"type": "webhook",
  "settings": {
  	"url": "https://example.com/timekit-webhook",
  	"method": "post",
  	"expected_response_code": "201"
  },
  "when": {
  	"type": "after",
  	"unit": "hours",
  	"time": 1
  }
}

Valid values for settings.method are "post" and "get".

The payload of the webhook request looks similar to the response you get when you [GET] the /bookings/:id endpoint.

App-level reminders

Setting up reminders on app-level is done through our admin interface: https://admin.timekit.io

Project-level reminders

Setting up reminders on a project is done by providing the 'reminders' attribute when creating or updating a project, like so:

curl --request PUT \
  --url https://api.timekit.io/v2/projects/<id> \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{
  "reminders": [
    {
    	"type":"email",
      "settings": { 
      	"recipient": "owner", 
        "subject": "Time for take-off!"
      },      
      "when": {
      	"type": "before", 
        "unit": "mins", 
        "time": "15"
      }
    }
  ]
}'

Please note that you are not limited to one single reminder per project.

Booking-level reminders

You can also setup reminders specifically for each single booking you make. Notice that reminders are called event_notifications when setting them on the booking!

curl --request POST \
	--url https://api.timekit.io/v2/bookings \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{
  "resource_id": <id>,
	"graph": "instant",
	"action": "confirm",
	"customer": {
		"name": "Marty McFly",
    "email": "marty.mcfly@timekit.io"
	},
	"event": {
		"start": "2016-11-23 15:00:00",
		"end": "2016-11-23 16:00:00",
		"what": "Mens haircut",
		"where": "Sesame St, Middleburg, FL 32068, USA",
		"calendar_id": <calendar_id>
	},
	"event_notifications": [
		{
			"type": "webhook",
			"settings": {
				"url": "https://example.com/timekit-webhook",
				"method": "post",
				"expected_response_code": 200
			},
			"when": {
				"type": "after",
				"unit": "hours",
				"time": 24
			}
		}
	]
}

This example sets up a webhook-reminder, to be triggered 24 hours after the booking began.

Graphs overview

Graphs are the blueprints/workflows that bookings follow during their lifetimes.

 

For an introduction to graphs please refer to our introduction article.

Auto-complete

All graphs include the default behaviour that the booking automatically will transition to the 'completed' state, one hour after the booking has taken place.

You can disable this default behaviour by adding the 'auto_complete_one_hour_after_booking_ends' attribute when creating the booking:

auto_complete_one_hour_after_booking_ends:{
    enabled: false
}

This is useful if you want to register no-shows. Then you would disable auto-complete and only manually register the booking as complete, when the customer is registered as showing up. You would register this by calling /bookings/:id/:action with action = complete

Instant

The instant graph is used for the situations where the booking request is automatically confirmed, i.e. the booked user doesn't need to confirm the booking.

 

Create bookings with the instant graph with the action 'confirm', to immediately block availability for the resource.

If the customer (the person who's making the booking request) chooses to cancel the booking, the flow reaches the state cancelled_by_customer and out of the box Timekit sends a cancellation email to the owner.

If the customer doesn't cancel, the booking will reach the state completed one hour after the booking has ended, as described under auto-complete

Available actions

  • confirm :arrow-right+: state=confirmed
  • cancel :arrow-right+: state=cancelled
  • cancel_by_customer :arrow-right+: state=cancel_by_customer
  • complete :arrow-right+: state=completed

Available webhook states

  • confirmed
  • error
  • completed
  • cancelled
  • cancelled_by_customer

Instant payment

The instant_payment graph reserves the booked time-slot when created and automatically frees the time-slot if a payment isn't registered within 5 minutes.

For a complete tutorial on how to implement payments, please read this tutorial in out help center: http://help.timekit.io/working-with-the-api/recipes/integrating-payments

 

When you register the payment, by applying the pay action to the booking, you can supply a payment_id to the request, like so:

curl --request PUT \
     --url https://api.timekit.io/v2/bookings/9d3fc349-5605-4bbf-a8fd-270fee55c137/pay \
     --header 'Content-Type: application/json' \
     --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
     --data '{
          "pay": {
            "payment_id": ":payment_id_string"
          }
        }'

Available actions:

  • create :arrow-right+: state=tentative

When in tentative state

  • timeout :arrow-right+: state=unpaid
  • pay :arrow-right+: state=paid

When in paid state

  • cancel :arrow-right+: state=cancelled
  • complete :arrow-right+: state=completed

Available webhook states

  • tentative
  • paid
  • cancelled
  • unpaid
  • completed
  • error

Confirm / decline

Use the confirm_decline graph when you have to make sure the booking request is confirmed before the booked timeslot is unavailable and an event is added to the resource's calendar.

For a tutorial on how you would confirm a booking, please read this tutorial in our help center: http://help.timekit.io/working-with-the-api/bookings/confirming-bookings

 

The confirm_decline graph goes through these states:

Tentative: When a customer makes a bookings request ([POST] /bookings with action='create') it is in tentative state waiting for either the confirm or decline action to be applied. Out of the box Timekit will send an email to the owner (the resource being booked) with links to confirm or decline the request. You can disable these emails from our admin dashboard. If you do this you must control the flow by calling /bookings/:id/:action so that the booking to passes down through the booking graph.

If the booking request is confirmed, the booking reaches the state confirmed and again out of the box, Timekit sends a confirmation email to the customer (unless you have disabled them).

If no further action is applied after that, the booking will reach the state completed one hour after the booking has ended, as described under auto-complete

If the booking is canceled /bookings/:id/:action action='cancel', the flow reaches the canceled state and Timekit will out of the box send a cancellation email to the owner.

Available actions

  • Create :arrow-right+: state=tentative

When in tentative state

  • Confirm :arrow-right+: state=confirmed
  • Decline :arrow-right+: state=declined

When in confirmed state

  • Cancel :arrow-right+: state=cancelled
  • Complete :arrow-right+: state=completed

Available webhook states

  • Tentative
  • Confirmed
  • Declined
  • Error
  • Cancelled
  • Completed

Group owner

In a booking where a number of seats are bookable, like in a seats in a class. Group_owner is the main booking, specifying when the class takes place. The group_customer graph is for handling each seat-booking.

For a complete tutorial on group bookings, please refer to this article in our help center: http://help.timekit.io/working-with-the-api/bookings/group-bookings

 

One special setting is important when creating a group_owner booking and that is the max_seats setting. This setting specifies the available number of seats.

This example creates a lecture class with 20 seats available.

curl --request POST \
     --url https://api.timekit.io/v2/bookings \
     --header 'Content-Type: application/json' \
     --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
     --data '{
          "resource_id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879"
          "graph": "group_owner",
          "action": "create",
          "settings": {
            "max_seats": 20,
            "min_cancel_time": "1 day",
            "min_booking_time": "2 hours",
            "max_booking_time": "14 days"
          },
          "start": "2016-09-30T08:00:00+00:00",
          "end": "2016-09-30T09:00:00+00:00",
          "what": "Doc Brown's lecture on flox capacitance",
          "where": "Sesame St, Middleburg, FL 32068, USA",
          "calendar_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
          "description": "Please arrive 10 minutes before classes begin"
        }'

The extra settings like "min_cancel_time" are optional, but this is their meaning:

min_cancel_time: Specifies the time cancellation can be done in relation to event begin time. In the example, any cancelation may be done at least 1 day/24 hours before the event starts.
min_booking_time: Specifies the minimum time that the booking must be created, before the event starts. In the example, any bookings must be created 2 hours before the event starts.
max_booking_time: Specifies the maximum time that the booking must be before the event starts. In the example, the bookings can first be created 14 days before event start.

Available actions

  • create :arrow-right+: state=tentative

When in tentative state

  • cancel :arrow-right+: state=cancelled
  • complete :arrow-right+: state=completed

Available webhook states

  • tentative
  • cancelled
  • completed
  • error

Group customer

The group_customer graph is for booking each seat specified in the group_owner booking

 

When creating a group_customer booking you must reference the group_owner booking like so

--request POST \
     --url https://api.timekit.io/v2/bookings \
     --header 'Content-Type: application/json' \
     --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
     --data '{
          "resource_id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
          "graph": "group_customer",
          "action": "create",
          "related": {
            "owner_booking_id": "a1ebdd9d-db42-4cd3-a915-0202a034284a"
          },
          "customer": {
            "name": "Marty McFly",
            "email": "Marty.McFly@example.com"
          }
        }'

Available actions

  • create :arrow-right+: state=confirmed
  • complete :arrow-right+: state=completed
  • cancel_by_customer :arrow-right+: state=cancelled_by_customer
  • cancel_by_owner :arrow-right+: state=cancelled_by_owner

Available webhooks states

  • confirmed
  • completed
  • error
  • cancelled_by_customer
  • cancelled_by_host

Group customer payment

The group_customer_payment graph is used when you want to ensure that the customer has paid for the seat, before the seat is unavailable.

 

You must apply the action pay in order for the seat to be booked/unavailable.

Available actions

  • create :arrow-right+: state=tentative

When in tentative state

  • cancel_by_owner :arrow-right+: state=cancelled_by_customer
  • pay :arrow-right+: state=paid
  • timeout (automatic) :arrow-right+: state=unpaid

When in paid state

  • cancel_by_owner :arrow-right+: state=cancelled_by_owner
  • complete :arrow-right+: state=completed
  • cancel_by_customer :arrow-right+: state=cancelled_by_customer

Available webhook states

  • tentative
  • unpaid
  • paid
  • cancelled_by_owner
  • cancelled_by_customer
  • completed
  • error

Projects overview

Understand Timekits project model

 

Projects acts as event types for your different booking flows in Timekit. In your project you can define which resources are available to book, which booking blueprint to use, how availability is calculated and many other things that all make up your booking experience.

Projects are optional to use as you can achieve the same results by persisting information on your end. But because they are supported through our admin panel, they provide you with an easy to use abstract container that glues together resources, availability and booking settings.

Using the legacy projects?

The projects endpoints are interfaces to our updated projects model in Timekit, released in spring 2018. These are separate entities from the previous version of projects (also known as "widgets" in technical terms), which are not accessible through our API.

Create a project

Create a project

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/projects
curl --request POST \
  --url https://api.timekit.io/v2/projects \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{
  "name": "My Test Project",
  "slug": "my-test-project",
  "resources": [
    "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
    "a728e860-99c7-4009-8843-7d9ac5d7f53f"
  ],
  "availability": {
    "mode": "roundrobin_random",
    "length": "15 minutes",
    "from": "1 hour",
    "to": "4 weeks",
    "buffer": "15 minutes",
    "ignore_all_day_events": false
  },
  "availability_constraints": [
    { "allow_day_and_time": { "day": "monday", "start": 1, "end": 10 } },
    { "allow_day_and_time": { "day": "tuesday", "start": 1, "end": 10 } },
    { "block_period": { "start": "2018-05-01", "end": "2018-05-06" } }
  ],
  "booking": {
    "graph": "instant",
    "what": "Test Bookings",
    "where": "TBA",
    "description": "The lightning strikes at 10:04 PM exactly!",
  },
  "reminders": [
    {
      "settings": { "recipient": "owner", "subject": "Time for take-off!"},
      "type":"email",
      "when": {"type": "before", "unit": "mins", "time": "15"}
    }
  ],
  "customer_fields": {
    "name": {
      "title": "Name",
      "prefilled": '',
      "readonly": false
    },
    "email": {
      "title": "E-mail",
      "prefilled": '',
      "readonly": false
    },
    "comment": {
      "title": "Comment",
      "required": true,
      "prefilled": '',
      "readonly": false
    }
  },
  "ui": {
    "display_name": "Martys Timetravel Service",
    "avatar": "",
    "availability_view": "agendaWeek",
    "show_credits": true,
    "time_date_format": '12h-mdy-sun',
    "localization": {
      "allocated_resource_prefix": 'with',
      "submit_button": 'Book it',
      "success_message": 'Thanks for booking!'
    }
  },
  "meta": {
  	"external_id": 11223344,
    "store_location": "9303 Lyon Drive, Lyon Estates, Hill Valley CA 95420"
  }
}'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "826ddc8e-8698-45be-9320-0c81dcf797d9",
    "name": "My Test Project",
    "slug": "my-test-project",
    "resources": [
      "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
      "a728e860-99c7-4009-8843-7d9ac5d7f53f"
    ],
    "availability": {
      "mode": "roundrobin_random",
      "length": "15 minutes",
      "from": "1 hour",
      "to": "4 weeks",
      "buffer": "15 minutes",
      "ignore_all_day_events": false
    },
    "availability_constraints": [
      { "allow_day_and_time": { "day": "monday", "start": 1, "end": 10 } },
      { "allow_day_and_time": { "day": "tuesday", "start": 1, "end": 10 } },
      { "block_period": { "start": "2018-05-01", "end": "2018-05-06" } }
    ],
    "booking": {
      "graph": "instant",
      "what": "Test Bookings",
      "where": "TBA",
      "description": "The lightning strikes at 10:04 PM exactly!",
    },
    "reminders": [
      {
        "settings": { "recipient": "owner", "subject": "Time for take-off!"},
        "type":"email",
        "when": {"type": "before", "unit": "mins", "time": "15"}
      }
    ],
    "customer_fields": {
      "name": {
        "title": "Name",
        "prefilled": false,
        "readonly": false
      },
      "email": {
        "title": "E-mail",
        "prefilled": false,
        "readonly": false
      },
      "comment": {
        "title": "Comment",
        "required": true,
        "prefilled": false,
        "readonly": false
      }
    },
    "ui": {
      "display_name": "Martys Timetravel Service",
      "avatar": "http://via.placeholder.com/100x100",
      "availability_view": "agendaWeek",
      "show_credits": true,
      "time_date_format": '12h-mdy-sun',
      "localization": {
        "allocated_resource_prefix": 'with',
        "submit_button": 'Book it',
        "success_message": 'Thanks for booking!'
      }
    }
  }
}

Body Params

name
string
required

Give the project a name

slug
string

If a project with the same slug already exists, a validation error will be returned with a valid suggestion.

resources
array of strings
required

ID's of the resources that are available as par of this project

availability
array of strings
required

Configure how availability should be queried. Please see the reference for querying availability

availability_constraints
array

Configure any cross-resource constraints. Please see availability-constraints for reference.

booking
array of strings
required

Configure how bookings should be made. Please see the booking section below

reminders
array

Reminder settings specific to this project. Please see our "reminders" reference, for how to configure these

customer_fields
string

Configure which inputs the customer can add to the booking.

ui
array of mixed types

UI specific configuration used by our booking.js widget (v2) reference coming.

meta
array of mixed types

Meta data can be anything like external_ids or project locations

 

Create a new project.

Projects are meant to be used togehter with our fetch availability endpoint and the create bookings endpoint. It's a way to persistent configurations for these parts of Timekit at our end. Please note that you can always override the project settings in the request to the booking and availability endpoints.

Let's take a look at the properties you can set and what they do in 1-to-1 projects:

🔒Only available on Platform plan

Creating projects through the API is locked on the Essential and Professional plans. Please see our pricing page.

Availability

resources is a list of resource IDs that make your defined resources available for booking within specific the project. Please see the fetch availability endpoint.

availability contains the top-level parameters that the fetch availability endpoint takes. These should map 1:1 with what is specified on the endpoint

availability_constraints are you project-level availability constraints which are applied in addition to resource-level constraints defined directly on your resoruces. Please see the fetch availability endpoint.

Booking

booking contains the top-level parameters that the create booking endpoint takes. These should map 1:1 with what is specified on the endpoint

Please note that if you want to make a project that offers group bookings (classes etc.) you need to create the group_owner classes before they will be visible through the project. The project setting under booking.graph should likewise be set to group_customer because this is the kind of bookings that will end up being created through the project.

reminders are reminders (aka. "event notifications"), which are documented in depth here.

Presentation

customer_fields specifies which inputs you want your customers to fill out when making a booking. If you use our booking.js widget, the fields you declare are rendered on the form screen. Please see the booking.js docs for a full reference.

ui are miscellaneous UI specific settings that are meant to instruct how the booking flow for your customers should behave. Our booking.js v2 widget uses these when embedded on your own web page or on our hosted URL. If you're building your own UI, you can use these as hints on how to render to your component, although it's completely optional.

Attach meta data to projects

meta is extra data you can attach to the project, stored as key-value pairs. This could be an external_id from your own system or maybe the address of the store the project represents.
This data will be searchable via /projects endpoint, see: https://developers.timekit.io/v2/reference#projects

Many-to-1 (group bookings)

Using projects for group bookings is different from the default 1-to-1 bookings. Essentially, the only required setting is booking: { graph: 'group_customer' } and optionally customer_fields and ui. Bookable slots are created as bookings with the group_owner graph which you link together with the project by passing project_id parameter to the booking created.

List all projects

List projects

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/projects
curl --request GET \
  --url https://api.timekit.io/v2/projects \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "data": [{
    "id": "826ddc8e-8698-45be-9320-0c81dcf797d9",
    "name": "My Test Project",
    "slug": "my-test-project",
    "resources": [
      "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
      "a728e860-99c7-4009-8843-7d9ac5d7f53f"
    ],
    "availability": {
      "mode": "roundrobin_random"
    },
    "availability_constraints": [],
    "booking": {
      "graph": "instant",
    },
    "reminders": [],
    "customer_fields": {
      "name": {
        "title": "Your name"
      },
      "email": {
        "title": "Your e-mail"
      },
      "comment": {
        "title": "Your comment",
        "prefilled": 'This value cannot be edited',
        "readonly": true
      }
    },
    "ui": {}
  }, {
    "id": "926ddc8e-8698-45be-9320-0c81dcf797d9",
    "name": "My Second Project",
    "slug": "my-second-project",
    "resources": [
      "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
      "a728e860-99c7-4009-8843-7d9ac5d7f53f"
    ],
    "availability": {
      "mode": "roundrobin_random"
    },
    "availability_constraints": [],
    "booking": {
      "graph": "instant",
    },
    "reminders": [],
    "customer_fields": {
      "name": {
        "title": "Name"
      },
      "email": {
        "title": "E-mail"
      }
    },
    "ui": {}
  }]
}
 

Retrieve all projects.

Search

Possible search attributes are:

  • resource.id which will return all projects where the resource is either one of the bookable resources or the creator of the project.
  • meta.{key}:{value} which will return all projects where the metadata {key} is equal to {value}. Example: /v2/projects?search=meta.external_id:112233

Update a project

You can atomically update the different settings in a project, this mean that only the settings that you input are updated, so you don't have to provide the entire project JSON in order to update a single setting.

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/projects/id
curl --request PUT \
  --url https://api.timekit.io/v2/projects/<id> \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{
  "availability": {
    "length": "1 hour"
  }
}'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

The ID of the project you want to update

 

Atomicity on arrays

Please note that when updating an array-attribute ("reminders", "availability_constraints", "meta"), you will be setting the entire array and not just adding to the existing array!

Delete a project

Delete a specific project

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.timekit.io/v2/projects/id
curl --request DELETE \
  --url https://api.timekit.io/v2/projects/1a54db8e-46c3-48b6-8644-6ffd164de1b6 \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

ID of the project you want to delete

 

Add resources to a project

You can add one or more resources to a project using this endpoint

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/projects/id/resources
curl --request POST \
  --url https://api.timekit.io/v2/projects/<id>/resources \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{ 
  	"resource_id": "<id>"
	}'
curl --request POST \
	--url https://api.timekit.io/v2/projects/<id>/resources \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{ 
  	"resources": [
    	"<id>",
      "<id>",
      "<id>"
    ]
	}'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

resource_id
string
required

ID of the resource you want to add to the project

 

Set resources on a project

This will set the resources, any existing resource will be removed and replaced by the once defined in the body.
The sequence of the resources will be reflected when using the roundrobin_prioritized mode.

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/projects/id/resources
curl --request PUT \
  --url https://api.timekit.io/v2/projects/<id>/resources \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '[
  	"<id>",
    "<id>",
    "<id>"
	]'
A binary file was returned

You couldn't be authenticated

Try the API to see results
 

Updates the resources connected to a project.

Replaces array

Please note that when updating this array-attribute, you will be setting the entire array and not just adding to the existing array!

Remove a resource from a project

You can remove a single resource from a project using the endpoint

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.timekit.io/v2/projects/project_id/resources/resource_id
curl --request DELETE \
  --url https://api.timekit.io/v2/projects/<project_id>/resources/<resource_id> \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

project_id
string
required

ID of the project

resource_id
string
required

ID of the resource you want to remove

 

Remove a specific resource from a project

Get resources for a project

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/project/id/resources
curl --request GET \
  --url https://api.timekit.io/v2/projects/<id>/resources \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
A binary file was returned

You couldn't be authenticated

{"data":["4de5bd0b-953b-4a48-8068-9ba712382d79","28f7ebe5-7e2e-4a1f-a012-95f8b074b3fe"]}
 

Retrieve credentials

Credentials are attached to a specific resource and can be used for resource based authentication when using the Booking.js widget or the JavaScript SDK.

If you are not using the widget, you do not need to use resource credentials and should always be using the regular app API-Key authentication.

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/credentials
curl --request GET \
  --url https://api.timekit.io/v2/credentials \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "total": 2,
  "per_page": 50,
  "current_page": 1,
  "last_page": 1,
  "next_page_url": null,
  "prev_page_url": null,
  "from": 1,
  "to": 2,
  "data": [
    {
      "id": "9c477a4c-f6c2-48b5-a472-b1a394fe4d3d",
      "type": "client-token",
      "description": "Token generated on user creation",
      "token": "CyBm1Po88ulqyYLrcc1mMmlYaHyetdO7",
      "scopes": [
        "widget"
      ],
      "token_generated_at": "2018-03-06T10:55:56+0100",
      "updated_at": "2018-03-06T10:55:56+0100"
    }
  ]
}
 

Are you not using Booking.js v1?

Resource credentials are only meant to be used as authentication for the Booking.js widget - for any other part of the Timekit API, you should be using app API-Key authentication.

When using credentials on the frontend, ONLY use the ones with the type client-token.

Search

Searchable attributes:

  • resource.id

What about server-tokens?

Resource credentials of the type server-token are present in Timekit for historical reasons. They are still here to ensure backwards compatability for users that have built their Timekit integrations using these. However, we strongly encourage new Timekit users to use our app API-Key based authentication.

Finding credentials for a resource

When you have the id of a resource, you can use the /credentials endpoint to find that resource's credentials with this query:

curl --request GET \
  --url https://api.timekit.io/v2/credentials?search=resource.id:2939c4fa-f06f-4496-8a20-03f57afcdfe6 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7

This will return the credentials for that specific resource only. When using Booking.js, you should only use credentials of the type client-token. Credentials of the client-token type are safe to use on the frontend and only has access to a limited number of endpoints.

Frontend safe credentials

When using credentials on the frontend, ONLY use credentials with the type client-token. These tokens are safe to use on the frontend.

Alternatively, when you are querying the /resources endpoint, you can include the user's credentials, using dynamic includes:

curl --request GET \
  --url https://api.timekit.io/v2/resources/2939c4fa-f06f-4496-8a20-03f57afcdfe6?include=credentials \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7

This will return both the resource and the credentials belonging to it.

Create a calendar

Create an additional calendar for a resource.

When a resource is created, it is automatically given a default calendar. So you only ever need to use this endpoint in case you need more than one calendar for your resources.

 
posthttps://api.timekit.io/v2/calendars
curl --request POST \
  --url https://api.timekit.io/v2/calendars \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
  "resource_id": "78a4d873-2a68-41c6-bdd4-c0ca5b35efd3",
  "name": "Important encounters with Marty",
  "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness",
  "foregroundcolor": "#000000",
  "backgroundcolor": "#FFFFFF"
}'
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
    "name": "Important encounters with Marty",
    "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness",
    "foregroundcolor": "#000000",
    "backgroundcolor": "#FFFFFF",
    "provider_id": "my-calendar",
    "provider_access": "owner",
    "provider_primary": false,
    "provider_sync": false,
    "created_at": "2016-02-29T18:41:38+0100",
    "updated_at": "2016-06-02T23:00:03+0200"  }
}

Body Params

resource_id
string
required

The ID of the resource that you want to created the calendar for

name
string
required

Name of the calendar

description
string
required

Description of the calendar

backgroundcolor
string

Hex color to use as background color for events in this calendar

foregroundcolor
string

Hex color to use as foreground color for events in this calendar

 

List all calendars

List calendars

 
gethttps://api.timekit.io/v2/calendars
curl --request GET \
  --url https://api.timekit.io/v2/calendars \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "provider_id": "important-encounters-with-marty",
      "provider_access": "reader",
      "provider_primary": false,
      "provider_sync": false,
      "created_at": "2016-02-29T18:41:38+0100",
      "updated_at": "2016-06-02T23:00:03+0200"
    },
    {
      "id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
      "name": "My personal calendar",
      "display_name": "My personal calendar",
      "description": "Notes to self, so I don't remember to to them.",
      "foregroundcolor": "#25d6be",
      "backgroundcolor": "#ea1cb8",
      "provider_id": "my-personal-google-calendar",
      "provider_access": "owner",
      "provider_primary": true,
      "provider_sync": true,
      "created_at": "2016-02-29T18:41:38+0100",
      "updated_at": "2016-06-02T23:00:03+0200"
    }
  ]
}
Invalid credentials.
 

Search

Searchable attributes:

  • resource.id

Dynamic includes

Available includes:

  • events

Retrieve a calendar

Get a specific calendar

 
gethttps://api.timekit.io/v2/calendars/id
curl --request GET \
  --url https://api.timekit.io/v2/calendars/c91c5d04-2a57-46c0-ab35-e489dadf132e \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
    "name": "My personal calendar",
    "display_name": "My personal calendar",
    "description": "Notes to self, so I don't remember to to them.",
    "foregroundcolor": "#25d6be",
    "backgroundcolor": "#ea1cb8",
    "provider_id": "my-personal-google-calendar",
    "provider_access": "owner",
    "provider_primary": true,
    "provider_sync": true,
    "created_at": "2016-02-29T18:41:38+0100",
    "updated_at": "2016-06-02T23:00:03+0200"
  }
}
Invalid credentials.
{
  "error": {
    "message": "Resource Not Found",
    "status_code": 404
  }
}

Path Params

id
string
required

Id of the calendar

 

Update a calendar

Update a calendar

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.timekit.io/v2/calendars/id
curl --request PUT \
  --url https://api.timekit.io/v2/calendars/id
var request = require("request");

var options = { method: 'PUT',
  url: 'https://api.timekit.io/v2/calendars/id' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://api.timekit.io/v2/calendars/id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Put.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("PUT", "https://api.timekit.io/v2/calendars/id");

xhr.send(data);
import requests

url = "https://api.timekit.io/v2/calendars/id"

response = requests.request("PUT", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Body Params

name
string

Name of the calendar

description
string

Description of the calendar

foregroundcolor
string

Hex color code for the foreground-color on the form #RRGGBB

backgroundcolor
string

Hex color code of the background-color on the form #RRGGBB

provider_sync
boolean

Enable or disable syncing.

primary
boolean

Set the calendar as the primary

 

Calendars provided by external services like Google cannot be updated! Only enabling or disabling of sync is possible for externally provided calendars. You can update externally provided calendars through the external services.

Only the parameter present in the request body will be updated, any other values will be left unchanged.

The setting of primary will affect which calendar is used in /bookings if you do not supply calendar_id in those requests.

Delete a calendar

Delete a calendar

 
deletehttps://api.timekit.io/v2/calendars/:id
curl --request DELETE \
  --url https://api.timekit.io/v2/calendars/bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2 \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7
A binary file was returned

You couldn't be authenticated

Path Params

:id
string
required

The ID of the calendar

 

You can delete a calendar on the Timekit platform by using this endpoint. You can delete any calendar if the resource doesn't have a connected google account

If the user/resource has a connected Google account, you can only delete calendars that have been created using the [POST] /calendars endpoint. This is to avoid private calendars are deleted in error (or abused) without consent of the Google account owner.

Create an event

Create an event in a calendar to block availability

 
posthttps://api.timekit.io/v2/events
curl --request POST \
  --url https://api.timekit.io/v2/events \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{
       "resource_id": "78a4d873-2a68-41c6-bdd4-c0ca5b35efd3",
       "start": "1983-06-08T10:00:00-07:00",
       "end": "1983-06-08T20:00:00-07:00",
       "what": "Sweep Doc's garage",
       "where": "Doc's house",
       "calendar_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
       "all_day": false,
       "description": "I promised Doc that I'll sweep his garage, so I won't be available for any other appointments at that time."
    }'
A binary file was returned

You couldn't be authenticated

{
    "data": {
        "id": "fae6d156-bc5c-4bfe-97db-d7b6a9d83061",
        "what": "Sweep Doc's garage",
        "where": "Doc's house",
        "description": "I promised Doc that I'll sweep his garage, so I won't be available for any other appointments at that time.",
        "rsvp": "needsAction",
        "allDay": false,
        "start": "1983-06-08T10:00:00-07:00",
        "end": "1983-06-08T20:00:00-07:00",
        "created_at": "2017-11-16T08:41:47+0000",
        "updated_at": "2017-11-16T08:41:47+0000"
    }
} 
{ }

Body Params

calendar_id
string
required

Uuid of the calendar to add the event to

start
date
required

Start of the event

end
date
required

End of the event

what
string
required

What is the event? 'Strategy meeting' or 'Coffee with Peter'

where
string
required

Where is the event taking place?

description
string

A custom description for the event

invite
boolean

Send provider invitation emails when using google/microsoft. See below.

participants
array of strings

A list of emails to invite as participants (when using google/microsoft)

my_rsvp
string

Set your own RSVP when using google/microsoft, allowed values: "accepted", "needsAction", "declined", "tentative"

all_day
boolean

if set to true, we will only send date (Y-m-d) to google, so it will be handled as a true all day event

sync_provider
boolean

This will trigger a sync with the associated provider and return the Event object from the database

available
boolean

If set to true, the event will not block availability.

 

Events are entities that block availability in a calendar. Events should not be regarded as bookings they don't contain all the necessary booking data or follow any graphs.

But events can come in handy if you need to control availability granularly. E.g. you use our /findtime endpoint and include availability filters to build a general availability profile, but you can use this endpoint to specifically block time in a resource's calendar.

Understanding the event invitations

If the booked resource is synced with an external service, like google or microsoft, the service can automatically send its own built in "invitation" notifications to the participants, once an event is put into a calendar. The invite parameter is false by default.

If you want invitations to be sent, make sure to include the customer's (recipient) email in the participants array, like so:

"participants": [
  "john@doe.com"
]

If you also add the resource's (event owner) email to the participants list in addition to the customer email, you can choose the initial RSVP status for event with the my_rsvp parameter.

List all events

List all events

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.timekit.io/v2/events
curl --request GET
  --url https://api.timekit.io/v2/events?start=2018-01-01T00:00:00+01:00&end=2018-02-01T00:00:00+01:00&search=resource.id:d187d6e0-d6cb-409a-ae60-45a8fd0ec879 \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW
A binary file was returned

You couldn't be authenticated

{
	"data": [
    {
      "id": "31c354d2-7249-4877-b9b7-d076e8e4b676",
      "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",
      "calendar_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "allDay": false,
      "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!.",
      "available": false
    },
    {
      "id": "8d30b27e-ffd3-4b41-a7c0-da334d4ebbdd",
      "start": "1955-11-05T09:30:00-07:00",
      "end": "1955-11-05T09:45:00-07:00",
      "what": "Deliver the Pacard to the auto shop",
      "where": "Western Auto Store, Hill Valley, CA 95420, USA",
      "calendar_id": "c91c5d04-2a57-46c0-ab35-e489dadf132e",
      "allDay": false,
      "description": "The clutch needs tightening",
      "available": false
    }    
  ]
}
{
  "errors": {
    "start": [
      "The start field is required."
    ],
    "end": [
      "The end field is required."
    ]
  }
}

Query Params

start
date-time
required

Start date to get events from

end
date-time
required

End date to get events to

search
string
 

If you want events for a particular calendar, you can call [[GET] /calendars/{:id}?include=events]
/calendars/:id

Dynamic includes

Available dynamic includes:

  • customers

Search

Available search parameters:

  • resource.id
  • calendar.id
  • available

Retrieve an event

Get a specific event

 
gethttps://api.timekit.io/v2/events/id
curl --request GET \
  --url https://api.timekit.io/v2/events/31c354d2-7249-4877-b9b7-d076e8e4b676 \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW
A binary file was returned

You couldn't be authenticated

{
  "data": {
    "id": "31c354d2-7249-4877-b9b7-d076e8e4b676",
    "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",
    "calendar_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
    "allDay": false,
    "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!.",
    "available": false
  }
}
{
  "error": "Resource does not exist"
}
{
  "errors": "You are not allowed to do this!"
}

Path Params

id
string
required

the id of the event

 

Update an event

Update a specific event

 
puthttps://api.timekit.io/v2/events/:id
curl --request PUT \
  --url https://api.timekit.io/v2/events \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW \
  --data '{
       "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",
       "calendar_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
       "allDay": false,
       "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!."
    }'
A binary file was returned

You couldn't be authenticated

No response examples available

Body Params

start
date-time
required

The new start time of the event

end
date-time
required

The new end time of the event

what
string

The new what of the event

where
string

The new where of the event

participants
array of strings

List of emails to invite

all_day
boolean

Is all day event?

available
boolean

If set to true, the event will not block availability

 

You can update any of the params in an event by calling this endpoint.

Delete an event

Delete a specific event

 
deletehttps://api.timekit.io/v2/events
curl --request DELETE \
  --url https://api.timekit.io/v2/events/31c354d2-7249-4877-b9b7-d076e8e4b676 \
  --header 'Content-Type: application/json' \
  --user :test_api_key_nvHfRSlhvsnlg4rS7Wt28Ty47qdgegwSu3YK7hPW
A binary file was returned

You couldn't be authenticated

No response examples available

Body Params

id
string

id of the event

 

Please note that this is not the same as cancelling a booking, in order to do that, use /bookings/:id/:action

Availability overview

 

A central feature of Timekit is searching for availability of your resources. Availability is timeslots that
your resources are open for booking i.e. spots where they are not already booked or blocked.

We support different modes/types of availability (team, mutual, bulk) and you can retrieve availability for a single resource or multiple at a time. Filters are used to further limit the search space, with the most common use case being opening hours.

➡️ If you want to learn more about Availability in Timekit, take a look in our Help Center.

Query availability

Query the availability of resources

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/findtime
curl --request POST \
  --url https://api.timekit.io/v2/findtime \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
           "resource_ids": [
             "78a4d873-2a68-41c6-bdd4-c0ca5b35efd3"
           ],					 
           "future": "2 days",
           "length": "4 hours"
         }'
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "start": "2017-12-07T00:00:00+01:00",
      "end": "2017-12-07T04:00:00+01:00"
    },
    {
      "start": "2017-12-07T04:00:00+01:00",
      "end": "2017-12-07T08:00:00+01:00"
    },
    {
      "start": "2017-12-07T08:00:00+01:00",
      "end": "2017-12-07T12:00:00+01:00"
    },
    {
      "start": "2017-12-07T12:00:00+01:00",
      "end": "2017-12-07T16:00:00+01:00"
    },
    {
      "start": "2017-12-07T16:00:00+01:00",
      "end": "2017-12-07T20:00:00+01:00"
    },
    {
      "start": "2017-12-07T20:00:00+01:00",
      "end": "2017-12-07T24:00:00+01:00"
    },
    {
      "start": "2017-12-08T00:00:00+01:00",
      "end": "2017-12-08T04:00:00+01:00"
    },
    {
      "start": "2017-12-08T04:00:00+01:00",
      "end": "2017-12-08T08:00:00+01:00"
    },
    {
      "start": "2017-12-08T08:00:00+01:00",
      "end": "2017-12-08T12:00:00+01:00"
    },
    {
      "start": "2017-12-08T12:00:00+01:00",
      "end": "2017-12-08T16:00:00+01:00"
    },
    {
      "start": "2017-12-08T16:00:00+01:00",
      "end": "2017-12-08T20:00:00+01:00"
    },
    {
      "start": "2017-12-08T20:00:00+01:00",
      "end": "2017-12-08T24:00:00+01:00"
    }
  ]
}
{
  "errors": {
    "emails": [
      "The emails field is required."
    ]
  }
}

Body Params

resource_ids
array of strings

Array of resource-uuid's. Will look in all the resource's calendars for blocking events

length
string

How much time must each available time-slot contain.

filters
array of mixed types

Filters to apply, see filter reference page

start
string

Defines the beginning of the search-space Written is human language, eg. 1 day, tomorrow, 2 weeks

future
string

Defines the end of the search-space (max 6 months)

sort
string

Chronological ascending (asc) or desceding (desc) order of results

ignore_all_day_events
boolean

Do you want to ignore all day event in this query?

all_solutions
boolean

Return all overlapping timeslots? (see note)

emails
array of strings

Array of emails to check for mutual availability

calendar_ids
array of strings

Array of uuid of calendars to check for mutual availability. Use this instead of resource_ids if you only want to look for availability in specific calendars

buffer
string

The amount of buffer you want to add to each booking. (see note)

no_day_span
boolean

If you do not want to get time-slots that span days. (see note)

 

Available until blocked

The default notion in Timekit is that a resource is available until blocked. Blocked meaning that an event is reserving time in the calendar or that some general business-rules, like opening-hours have been applied.
This is contrary to the use-cases where the baseline is: A given resource is only available in these pre-defined time-slots.

The "all_solutions" option

By default, the algorithm will return sequential available time-slots in the length duration you've specified. The available time-slots will not overlap, which means that some potential time-slots are ignored. If you want ALL time-slots (based on 15-minute intervals), then set "all_solutions" to true.

Example:
If we request time-slots of 1 hours length, from 10 to 12, without "all_solutions", these 2 time-slots will be returned:

  • 10:00-11:00
  • 11:00-12:00

If we request with "all_solutions":true, these 5 time-slots will be returned:

  • 10:00-11:00
  • 10:15-11:15
  • 10:30-11:30
  • 10:45-11:45
  • 11:00-12:00

Buffer Time

The buffer option makes sure that you have some breathing time between each available booking and any existing events in the calendar included in the availability check. Once an available time-slot has been booked and turned into a calendar event, it will too be included in the buffer time calculation.

You define buffer like you define length: "15 minutes", "1 hour" etc.

The "no_day_span" option

The "no_day_span" option means that no time-slots that start in one day end in another.
With the option being omitted(default) or set to false, these time-slots could be returned (looking for 2 hours):

  • 21:00-23:00
  • 23:00-01:00
  • 01:00-03:00

With "no_day_span" set to true, the same request would return these timeslots:

  • 21:00-23:00
  • 00:00-02:00

Mutual availability

You can search for mutual availability, in other words, find time-slots where several resources are simultaneously available. All you need to do is to add the ids of the resources you want to search for mutual availability, to resource_ids array.

Note that there can still only be one resource as "owner" of the booking, so if you include more resources, make sure to add them as customers to the final event to make sure their calendar is blocked too.

Bulk availability

Request several findtime queries in one go

 
posthttps://api.timekit.io/v2/findtime/bulk
curl --request POST \
  --url https://api.timekit.io/v2/findtime/bulk \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{[
          {
              "resource_ids": [
              	"fca27950-1be8-41e2-951c-a43a61d45d43"
              ],
              "filters": {
                  "or": [
                      { "specific_day": {"day": "Monday"} },
                      { "specific_day": {"day": "Friday"} }
                  ]
              },
              "future": "2 weeks"
          },
          {
              "resource_ids": [
              	"bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2"
              ],
              "filters": {
                  "or": [
                      { "specific_day": {"day": "Tuesday"} }
                  ]
              },
              "future": "1 weeks"
          }
      ]}'
A binary file was returned

You couldn't be authenticated

{
  "data": [
    [
      {
        "start": "2015-07-27 00:00:00 Monday",
        "end": "2015-07-27 01:00:00 Monday"
      },
      {
        "start": "2015-08-03 00:00:00 Monday",
        "end": "2015-08-03 01:00:00 Monday"
      },
      {
        "start": "2015-07-24 00:00:00 Friday",
        "end": "2015-07-24 01:00:00 Friday"
      },
      {
        "start": "2015-07-31 06:00:00 Friday",
        "end": "2015-07-31 07:00:00 Friday"
      }
    ],
    [
      {
        "start": "2015-07-24 00:00:00 Friday",
        "end": "2015-07-24 01:00:00 Friday"
      },
      {
        "start": "2015-07-24 01:00:00 Friday",
        "end": "2015-07-24 02:00:00 Friday"
      }
    ]
  ]
}

Body Params

#no-name#
array of mixed types

array of findtime queries

 

Works just the same way as a normal findtime query, but you can bulk them together in one request. See /findtime

This is useful if you need to apply some special business-logic to the result, where multiple roundtrips to the api introduces too much latency.

Team availability

Find time in a team independent of each members availability

 
posthttps://api.timekit.io/v2/findtime/team
curl --request POST \
  --url https://api.timekit.io/v2/findtime/team \
  --header 'Content-Type: application/json' \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
        "start": "2 days",
        "future": "2 weeks",
        "length": "1 hour",
        "resources": [
          {
              "resource_ids": [
                  "fca27950-1be8-41e2-951c-a43a61d45d43"
              ],
              "filters": {
                  "or": [
                      { "specific_day": {"day": "Monday"} }
                  ]
              }
          },
          {
              "resource_ids": [
                  "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2"
              ],
              "filters": {
                  "or": [
                      { "specific_day": {"day": "Tuesday"} }
                  ]
              }
          }
      ]
    }'
A binary file was returned

You couldn't be authenticated

[
    {
        "start": "2016-02-15T09:30:00+0000",
        "end": "2016-02-15T10:30:00+0000",
        "resources": [
            {
                "resource_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
                "calendar_ids": [
                    "f68979ff-27da-4afd-8d0c-847f9340331b"
                ]
            }
        ]
    },
    {
        "start": "2016-02-15T10:30:00+0000",
        "end": "2016-02-15T11:30:00+0000",
        "resources": [
            {
                "resource_id": "fca27950-1be8-41e2-951c-a43a61d45d43",
                "calendar_ids": [
                    "c91c5d04-2a57-46c0-ab35-e489dadf132e"
                ]
            },
            {
                "resource_id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
                "calendar_ids": [
                    "f68979ff-27da-4afd-8d0c-847f9340331b"
                ]
            }
        ]
    }
]

Body Params

start
string
required

When should we start looking for available time? Written is human language, eg. 1 day, tomorrow, 2 weeks

future
string
required

How long into the future should we look for mutual availability (max 6 months)

length
string
required

How long should the availability be?

all_solutions
boolean

Return all overlapping timeslots? (see note)

ignore_all_day_events
boolean

Do you want to ignore all day event in this query?

resources
array
required

An array of team members(resource_ids) with individual filters.

 

Team availability will produce an array of available timeslots, where any of the team members are available. Each timeslot will contain an array of the team-members that are available in the given period.

This is helpful when you have a team, where it is not important which member is available, just that someone is. For example if you have a tech-support team, where it doesn't matter who handles an incoming issue, just that someone in the team does.

Filters

Apply filters to your findtime requests, to narrow the search-space.

 

Usually a search space defined only by beginning and end is not specific enough for your use-case. Most commonly physical resources are constrained by working or opening hours. Availability filters make it easy to add these constraints to your findtime requests.

Filter types

  • OR filters
    Will include the resulting timeslots from any of the supplied filters. If you supply two filters with timeslots that doesn't overlap, they will both be added to the result. Consider it equivalent of coding an OR in a conditional statement (Filter1Result OR Filter2Result OR Filter3Result ...).

Example:

"filters": {
  "or": [
    {"specific_day": {"day": "Monday"} },
    {"specific_day": {"day": "Wednesday"} }
  ]
}

This will return time-slots only on Mondays and Wednesdays.

  • AND filters
    Will only include time-slots that fit within all of the supplied filters. Time-slots resulting from two different filters must overlap both filters to be included in the result. Consider it the equivalent of coding an AND in a conditional statement (Filter1Result AND Filter2Result AND Filter3Result ...)

Example

"filters": {
  "and":[
    { "specific_time": {"start": 10, "end": 16} }, 
    { "specific_time": {"start": 12, "end": 18} }
  ]
}

This will return time-slots from 12 to 16, because this is the overlapping time-space.

Combined example:

"filters": {
  "and":[
    { "specific_time": {"start": 10, "end": 16} }, 
    { "specific_time": {"start": 12, "end": 18} }
  ],
  "or": [
    {"specific_day": {"day": "Monday"} },
    {"specific_day": {"day": "Wednesday"} }
  ]
}

This will return time-slots from 12 to 16 only on Mondays and Wednesdays.

Quicklinks

And/Or filters:

All filters example primarily meant as a quick syntax reference:

"filters": {
  "or": [
    { "specific_day": {"day": "Monday"} },
    { "specific_day_and_time": {"day": "Wednesday", "start": 10, "end": 12, "timezone": "Europe/Copenhagen"}},
    { "between_timestamps": {"start": "2016-05-26T15:30:00+00:00", "end": "2016-05-28T18:00:00+00:00"}},
    { "exclude_weekend": {} },
    { "only_weekend": {} },
    { "specific_time": {"start": 9, "end": 15} }

  ],
  "and": [
    { "business_hours": {"timezone": "America/Los_angeles"} },
    { "daytime": {"timezone": "Europe/Copenhagen"}}
  ]
}

Between timestamps filter

Limit the search-space to between two timestamps.

Argument
Description
Required
Example

start

The start timestamp of the filter

yes

"2016-05-26T15:30:00+00:00"

end

The end timestamp of the filter

yes

"2016-05-28T18:00:00+00:00"

timezone

Set timezone

no

"Europe/Copenhagen"

"filters": {
  "and": [
    { "between_timestamps": {
      "start": "2016-05-26T15:30:00+02:00", 
      "end": "2016-05-28T18:00:00+02:00", 
      "timezone": "Europe/Copenhagen"}
    }
  ]
}

Adding availability instead of blocking out.

The between-timestamps filter can be used as a way to add availability, so instead of blocking anything off like you would normally do, you supply a list of between-timestamps as or-filters, defining the time-slots you want bookable.

Business hours filter

Can be used to find all solutions in business hours (9 - 18 (6pm)) in a specific timezone.

Argument
Description
Required
Example

timezone

The timezone the business should be in

no - Default will be the timezone in the request headers

"America/Los_angeles"

"filters": {
  "and": [
    { "business_hours": {"timezone": "America/Los_angeles"} },
    { "business_hours": {"timezone": "Europe/Copenhagen"} }
  ]
}

You can add more than 1 business hour filter!

If you add two business-hour as 'and' filters with two different timezones, you can make sure both timezones are in business hours! This will be useful if you need to set up a meeting between two resources working in different timezones.

Daytime filter

Will only show options where its daytime (7 - 23 (11pm)) in the given timezone

Argument
Description
Required
Example

timezone

The timezone the business should be in

no - Default will be the timezone in the request headers

"America/Los_angeles"

"filters": {
  "and": [
    { "daytime": {"timezone": "America/Los_angeles"} },
    { "daytime": {"timezone": "Europe/Copenhagen"} }
  ]
}

Exclude weekends filter

If you need to filter out weekends (Saturdays & Sundays) you can use this filter. It takes a single argument

Argument
Description
Required
Example

timezone

The timezone

no - default is the timezone in the header request

"Europe/Copenhagen"

"filters": {
  "and": [
    { "exclude_weekend": {}}
  ]
}

Only weekend filter

If you only need time-slots in the weekend use this filter. The filter takes a single argument:

Argument
Description
Required
Example

timezone

Only weekend of the given timezone

no - default is the timezone in the header request

"Europe/Copenhagen"

This simple filter will only give you time-slots during weekends.

"filters": {
  "and": [
    { "only_weekend": {}}
  ]
}

Specific day and time filter

If you only need time-slots for a specific day and time, you can use this filter. The filter takes 3 argument:

Argument
Description
Required
Example

day

The day you need timeslots for

yes

"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" or "Sunday"

start

The start hour for this filter (in 24 hour format)

yes

10

end

The end hour for this filter (in 24 hour format)

yes

16

"filters": {
  "and": [
    { "specific_day_and_time": {"day": "Monday", "start": 10, "end": 16}}
  ]
}

This will give you all time-slots on Mondays between 10 & 16.

Specific time filter

If you only need timeslots for a specific time interval, you can use this filter. The filter takes a single argument:

Argument
Description
Required
Example

start

The start hour for this filter (in 24 hour format)

yes

10

end

The end hour for this filter (in 24 hour format)

yes

16

timezone

That timezone the start & end hour should make

no - default from the request headers

"Europe/Copenhagen"

"filters": {
  "and": [
    { "specific_time": {"start": 10, "end": 16}}
  ]
}

Specific day filter

If you only need timeslots for a specific day, you can use this filter. The filter takes a single argument:

Argument
Description
Required
Example

day

The day you need timeslots for

yes

"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" or "Sunday"

"filters": {
  "and": [
    { "specific_day": {"day": "Monday"}}
  ]
}