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

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-token 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 uuid. Uuid looks like this: de305d54-75b4-431b-adb2-eb6b9e546014
Read more about uuids here

Timestamps

All timestamps must be and will be RFC3339 formatted

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())

Timezone

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.

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 token 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-Token authentication

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

Example authentication request via App-Token

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 App-Token does not use the email part of basic authentication, but in order to remain compatible we need to prefix the API token 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"

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-Token

 

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"
           ]
       }'
{
    "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",
  }
}
{
  "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)

 

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

Search

Possible search attributes are:

  • tags

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

name
string
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 overview

 

The /findtime endpoint is where you query the availability of your resources in order to know when they are available to be booked.

➡️ 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.

Availability 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"}}
  ]
}

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": "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!",
  "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": "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"
      }
    ]
  }
}

Query Params

includes
string

Include booking attributes such as event_info in the response

Body Params

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
settings
object

You can disable the double-bookings check with: { allow_double_bookings: true }

 
start
date-time
required

When the booking starts

end
date-time
required

When the booking ends

what
string
required

The title of the booking

description
string
required

a description of the booking

where
string
required

A description of the location of the booking

calendar_id
string

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

meta
object

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

 
action
string

Name of action that should be triggered right after creation. For more infomation on actions, please refer to the Graph section of this reference.

invite
boolean

See description under event

 

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 \
  --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
  • customer.email
  • calendar.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

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:

  • logs
  • attributes
  • customers
  • calendar
  • event
  • available_actions
  • meta
  • related_bookings (see group bookings)
  • owner_booking (see group bookings)

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

 

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.

Confirm a booking

Learn how to confirm a booking in Timekit

 

In order to confirm a tentative booking in Timekit, you need to apply the confirm action which will update the state of the booking. The way actions are applied to bookings is through the /bookings/:id/:action endpoint.

➡️ Please have a look at the "Update booking state" part of this reference to learn more.

Decline a booking

Learn how to decline a booking in Timekit

 

In order to decline a tentative booking in Timekit, you need to apply the decline action which will update the state of the booking. The way actions are applied to bookings is through the /bookings/:id/:action endpoint.

➡️ Please have a look at the "Update booking state" part of this reference to learn more.

Cancel a booking

Learn how to cancel a booking in Timekit

 

In order to cancel a confirmed booking in Timekit, you need to apply the cancel action which will update the state of the booking. The way actions are applied to bookings is through the /bookings/:id/:action endpoint.

➡️ Please have a look at the "Update booking state" part of this reference to learn more.

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": "2017-10-20T12:49:58+01:00",
            "end": "2017-10-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": "2017-10-20T12:49:58+01:00",
            "end": "2017-10-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": "2017-10-20T12:49:58+01:00",
            "end": "2017-10-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.",
            "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.

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

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 token 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?

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 token 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 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 '{
       "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",
       "allDay": 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

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?

calendar_id
string
required

Uuid of the calendar to add the event to

participants
array of strings

A list of emails to invite as participants

invite
boolean

See below

description
string

A custom description for the event

my_rsvp
string

Set your own rsvp, allowed values: accepted, needsAction, declined, tentative

sync_provider
boolean

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

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

 

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 invite parameter

If the booked resource is synced with an external service, like google, the service will automatically send its own built in "invitation" to the participants, once an event is put into a calendar.
The invite parameter lets you disable this feature.

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!."
    },
    {
      "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",
    }    
  ]
}
{
  "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

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!."
  }
}
{
  "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

The new start time of the event

end
date-time

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?

 

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