Developers

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

Introduction

A brief introduction to the API and core data types.

 

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

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

App specific requests

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

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

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

Root endpoint, versions, and protocol

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

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

CORS

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

UUID as IDs

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

Timezones

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

Examples:

  • Europe/Copenhagen
  • America/Los_Angeles

Undocumented attributes

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

Timestamps

Timestamps are a critical part of Timekit.

 

All timestamps in Timekit are RFC3339 / ISO 8601 / ATOM formatted. This is the default input and output format.

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

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

// Built-in with output in Zulu/UTC timezone:
// e.g. 2019-11-24T08:46:01Z

const date = new Date();
const isoDate = date.toISOString().split('.')[0]+'Z';

// Using moment.js with timezone offset:
// e.g. 2019-11-24T08:46:01+01:00

const moment = require('moment');
const date = new Date();
const isoDateOffset = moment(date).format(); 
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)

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

App based auth

 

Before you can start using our API you must sign up via our admin interface to register a new account (also known as "app" in technical terms).

In the admin interface, navigate to the "API Settings" section where you'll find your App API Key. This is the API Key that you'll use to authenticate with our API when making API requests.

Uses Basic Authentication

We use Basic Authentication over HTTPS. It's simple to use and works across almost every platform and code language available.

Note that basic auth usually requires a email/user-name and a password. But since the API key is tied directly to your app only, we don't need the email as identifier. This means that the username should be omitted (or supplied as an empty string) and the API key is the password.

Server-side integration

Calling our API is straightforward and only requires that the "Authorization" HTTP header is set to your API key. With most HTTP toolkits and SDKs, you don't have to set this manually.

Make a request using cURL

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

Notice the prefixing colon!

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

Make a request using our Javascript SDK

var timekit = require('timekit-sdk');

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

timekit.getBookings()
.then(function(response){
  console.log(response);
}).catch(function(response){
  console.log(response);
});

You can find documentation for our JS SDK on Github.

Using the "Try It" functionality in the docs

The "Try It" functionality lets you try each endpoint against Timekits API directly here in the docs! Pretty nifty, eh? We recommend using an api key for an app in test mode!

If you want to make a barebones HTTP call to our API, basic auth works by setting a Authorization header with your base64 encoded key (this tool can help with the encoding). 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".

Client-side integration

When calling our API from a client-side use-case, we're using a different key that's safe to expose publicly in your frontend. This only grants access to selected endpoints and only exposes a limited set of information. In most cases, this key is only used for out booking widget called booking.js.

In our admin interface, navigate to the "API Settings" and look for the App Widget Key.

Embedding our widget in a webpage is in most cases as easy as copying the embed code found in our admin panel. Just navigate to your project and click the "Share" button - the embed code already includes your App Widget Key.

Avoid making client-side integrations

The App Widget Key that we provide is primarily used for usage with out booking.js widget. We highly recommend that you do not use it for any other purposes.

If you want to call Timekit from your frontend, you should relay those API calls through your own backend from where you will call our API. In that way, you have control over access and better insight into requests, responses etc.

Get current app

Get the app for the authenticated App API-Key

 

Header Auth

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

You couldn't be authenticated

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

Query Params

include
string
 

Invite resources to app

Invite existing resources to your app

 

Header Auth

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

You couldn't be authenticated

Try the API to see results

Body Params

email
string

The email you want to invite to your app

 

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

Resources overview

 

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

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

Create a resource

Create a new resource

 

Header Auth

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

You couldn't be authenticated

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

Body Params

name
string
required

Set the name of the resource

timezone
string
required

Timezone of the resources

email
string

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

first_name
string

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

last_name
string

Last name of the resources

password
string

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

availability_constraints
array

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

image
string

Url of an image representing the resource

 

Create resources programmatically.

🔒Only available on Platform plan

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

Will your resources log into Timekit?

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

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

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

List all resources

Get all resources for the app

 

Header Auth

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

You couldn't be authenticated

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

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

Dynamic includes

Available includes:

  • calendars
  • properties
  • availability_constraints

Search

Possible search attributes are:

  • email

Retrieve a resource

Get a specific resource by ID

 

Header Auth

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

You couldn't be authenticated

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

Path Params

id
string
required

Id of the specific resource

 

Update a resource

Update a specific resource

 

Header Auth

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

You couldn't be authenticated

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

Path Params

id
string
required

id of the specific resource

Body Params

first_name
string

First name of the user

last_name
string

Last name of the user

timezone
string

User's timezone following "area/city" schema

password
string

User's password in cleartext

 

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.

Remove 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
 

A note of resource deletion

Deleting a resource is not a hard delete. Instead, you are dissociating it with your account. That means it can still be part of other accounts and if you want to re-create it, you need to invite it. If you try to create a resource that has previously been part of your account, you will see a "user already exists" error.

Resource Invitation: https://developers.timekit.io/reference#appsinvite

Availability constraints

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

 

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

Here's how a request would look like:

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

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

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

Availability overview

 

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

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

Using the old /findtime endpoint?

This endpoint is the successor to our (POST /findtime)[ref:findtime] endpoint and has been redesigned for speed and more flexibility. It supports our new Projects model.

Read our migration guide.
You can also read the old reference here.

Query availability

Query for availability of resources

 

Header Auth

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

You couldn't be authenticated

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

Body Params

project_id
string

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

mode
string

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

resources
array of strings

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

constraints
array

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

length
string

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

from
string

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

to
string

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

buffer
string

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

ignore_all_day_events
boolean

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

output_timezone
string

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

timeslot_increments
string

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

round_to_nearest_hour
boolean

If you dont want us to round up to nearest hour (for pretty timestamps) you can set this to false

 

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

Available until blocked

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

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

Project ID

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

Mode

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

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

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

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

Constraints

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

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

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

How availability is calculated

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

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

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

Buffer Time

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

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

Timeslot increments

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

Example without timeslot_increments:

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

Examples with timeslot_increments:

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

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

Deprecated ignore_all_day_events

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

Constraints

Use constraints to set general rules for availability.

 

Formerly known as "filters"

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

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

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

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

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

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

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

Available constraints

Day and time

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

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

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

Hours

Allow or block certain hours of the day.

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

Day

Allow or block a specific day.

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

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

Period

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

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

Weekends

Only allow or block weekends.

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

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

Bookings overview

 

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

Learn more

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

Group bookings

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

Webhooks

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

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

Create a booking

Use this endpoint to create a booking.

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

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

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.timekit.io/v2/bookings
curl --request POST \
  --header 'Content-Type: application/json' \
  --url https://api.timekit.io/v2/bookings \
  --user :live_api_key_7nzvc7wsBQQISLeFSVhROys9V1bUJ1z7 \
  --data '{
  "resource_id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
  "graph": "confirm_decline",
  "start": "2018-08-12T21:30:00-07:00",
  "end": "2018-08-12T22:15:00-07:00",
  "what": "Catch the lightning",
  "where": "Courthouse, Hill Valley, CA 95420, USA",
  "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!",
  "meta":{
    "latitude":"34.1381168",
    "longitude":"-118.3533783"
  },
  "customer": {
    "name": "Marty McFly",
    "email": "marty.mcfly@timekit.io",
    "phone": "(916) 555-4385",
    "voip": "McFly",
    "timezone": "America/Los_Angeles"
  }
}'
A binary file was returned

You couldn't be authenticated

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

Query Params

includes
string

Include booking attributes such as event_info in the response

Body Params

project_id
string

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

resource_id
string
required

The ID of the resource being booked

graph
string
required

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

customer
object
required

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

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

When the booking starts

end
date-time
required

When the booking ends

what
string
required

The title of the booking

where
string
required

A description of the location of the booking

description
string
required

a description of the booking

invite
boolean

Send provider invitation emails when using google/microsoft. False by default. See details in note below.

participants
array of strings

A list of emails to invite as participants (when using google/microsoft). See details in note below.

my_rsvp
string

Set your own RSVP when using google/microsoft. See details in note below.

calendar_id
string

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

settings
object

Additional settings. See below

 
meta
object

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

 
 

Settings

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

  • allow_double_bookings which defaults to false. If you want bookings to allow overlapping you can set this to true
{
  "resource_id": "d187d6e0-d6cb-409a-ae60-45a8fd0ec879",
  "graph": "confirm_decline",
  "start": "2018-08-12T21:30:00-07:00",
  "end": "2018-08-12T22:15:00-07:00",
  "what": "Catch the lightning",
  "where": "Courthouse, Hill Valley, CA 95420, USA",
  "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!",
  "customer": {
    "name": "Marty McFly",
    "email": "marty.mcfly@timekit.io",
    "phone": "(916) 555-4385",
    "voip": "McFly",
    "timezone": "America/Los_Angeles"
  },
  "settings": {
    "allow_double_bookings": true
  }
}

Understanding the "invite" flag

If the booked resource is synced with an external service, like Google or Microsoft, the service can automatically send its own built in "invitation" notifications to the participants, once an event is put into a calendar. This is controlled by the invite flag, which is false by default.

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

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

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

List all bookings

Use this endpoint to get all bookings

 

Header Auth

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

You couldn't be authenticated

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

Query Params

limit
int32

Pagination limit intervals (X means first X is returned)

page
int32

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

search
string

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

include
string

Dynamic includes

orderBy
string

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

sortedBy
string

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

start
date

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

end
date

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

 

Search

Possible search attributes are:

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

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

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

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

Dynamic includes

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

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

Retrieve a booking

Use this endpoint to get a specific booking

 

Header Auth

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

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "state": "confirmed",
    "graph": "confirm_decline",
    "completed": true,
    "created_at": "2016-02-11T12:39:45+0100",
    "updated_at": "2016-02-11T13:12:01+0100",
    "available_actions": [],
    "attributes": {
      "event_info": {
        "start": "1955-11-12T21:30:00-07:00",
        "end": "1955-11-12T22:15:00-07:00",
        "what": "Catch the lightning",
        "where": "Courthouse, Hill Valley, CA 95420, USA",
        "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}
{
  "error": "Resource does not exist",
  "model": "Timekit\Booking"
}

Path Params

id
string
required

The id of the booking

Query Params

include
string

Dynamic includes

 

For dynamic includes, see /bookings

Update booking state

Perform an action on a booking to update its state.

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

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

 

Header Auth

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

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "graph": "confirm_decline",
    "state": "confirmed",
    "completed": false,
    "created_at": "2016-02-11T11:58:45+0100",
    "updated_at": "2016-02-11T11:58:47+0100",
    "available_actions": [
      "decline",
      "confirm"
    ],
    "attributes": {
      "event_info": {
        "start": "1955-11-12T21:30:00-07:00",
        "end": "1955-11-12T22:15:00-07:00",
        "what": "Catch the lightning",
        "where": "Courthouse, Hill Valley, CA 95420, USA",
        "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}

Path Params

id
string
required

The ID of the booking

action
string
required

Which action to trigger

Body Params

apply_to_bulked_bookings
boolean

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

 

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

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

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

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

Common actions

Confirm a booking: use the action confirm

Decline a booking: use the action decline

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

Update booking meta data

Update meta data related to a given booking.

 

Header Auth

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

You couldn't be authenticated

{
  "data": {
    "id": "58190fc6-1ec0-4ebb-b627-7ce6aa9fc703",
    "graph": "confirm_decline",
    "state": "confirmed",
    "completed": false,
    "created_at": "2016-02-11T11:58:45+0100",
    "updated_at": "2016-02-11T11:58:47+0100",
    "available_actions": [
      "decline",
      "confirm"
    ],
    "attributes": {
      "event_info": {
        "start": "1955-11-12T21:30:00-07:00",
        "end": "1955-11-12T22:15:00-07:00",
        "what": "Catch the lightning",
        "where": "Courthouse, Hill Valley, CA 95420, USA",
        "description": "The lightning strikes at 10:04 PM exactly! I need you to be there Doc!"
      }
    },
    "calendar": {
      "id": "bfa0b9fa-36aa-4ae6-8096-f3b20fbed1d2",
      "name": "Important encounters with Marty",
      "display_name": "Important encounters with Marty",
      "description": "Througout time, Marty and I really need to meet in order for the world not to collapse into Biffy cazyness.",
      "foregroundcolor": "#000000",
      "backgroundcolor": "#FFFFFF",
      "created_at": "2016-02-15T13:21:42+0100",
      "updated_at": "2016-02-15T13:21:42+0100"
    },
    "customers": [
      {
        "id": "a728e860-99c7-4009-8843-7d9ac5d7f53f",
        "name": "Marty McFly",
        "email": "marty.mcfly@timekit.io",
        "phone": "(916) 555-4385",
        "voip": "McFly",
        "timezone": "America/Los_Angeles"
      }
    ]
  }
}

Path Params

id
string
required

The ID of the booking

Body Params

meta
object

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

 
 

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

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

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

List all group bookings

Return all available (tentative) group bookings

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

 

Header Auth

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

You couldn't be authenticated

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

Query Params

limit
int32

Pagination limit intervals (X means first X is returned)

page
int32

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

search
string

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

 

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

Dynamic includes

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

Retrieve a group booking

Get a specific group booking

 

Header Auth

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

You couldn't be authenticated

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

Path Params

:id
string
required

ID of the booking

 

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

Dynamic includes

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

Create bookings in bulk

Use this endpoint to create bookings in bulk

 

Header Auth

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

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

You couldn't be authenticated

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

Body Params

bookings
array
required
delete_all_on_error
boolean

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

stop_on_first_error
boolean

If set to true execution will stop on the first error

relate_bookings
boolean

Create relation between the bulked bookings.

 

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

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

Related bulked bookings

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

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

Update bookings in bulk

Bulk update bookings

 

Header Auth

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

You couldn't be authenticated

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

Body Params

bookings
array
required
stop_on_first_error
boolean
reset_all_on_error
boolean
 

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

Delete a booking

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

 

Header Auth

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

You couldn't be authenticated

Try the API to see results
 

Reminders

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

 

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

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

Email reminders

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

The emails will look like this in the recipients inbox:

email example

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

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

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

Webhook reminders

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

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

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

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

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

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

App-level reminders

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

Project-level reminders

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

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

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

Booking-level reminders

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

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

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

Graphs overview

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

 

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

Auto-complete

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

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

auto_complete_one_hour_after_booking_ends:{
    enabled: false
}

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

Instant

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

 

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

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

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

Available actions

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

Available webhook states

  • confirmed
  • error
  • completed
  • cancelled
  • cancelled_by_customer

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

Projects overview

Understand Timekits project model

 

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

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

Using the legacy projects?

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

Create a project

Create a project

 

Header Auth

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

You couldn't be authenticated

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

Body Params

name
string
required

Give the project a name

slug
string

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

resources
array of strings
required

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

availability
array of strings
required

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

availability_constraints
array

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

booking
array of strings
required

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

reminders
array

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

customer_fields
string

Configure which inputs the customer can add to the booking.

ui
array of mixed types

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

meta
array of mixed types

Meta data can be anything like external_ids or project locations

 

Create a new project.

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

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

🔒Only available on Platform plan

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

Availability

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

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

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

Booking

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

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

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

Presentation

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

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

Attach meta data to projects

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

Many-to-1 (group bookings)

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

List all projects

List projects

 

Header Auth

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

You couldn't be authenticated

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

Retrieve all projects.

Search

Possible search attributes are:

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

Update a project

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

 

Header Auth

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

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

The ID of the project you want to update

 

Atomicity on arrays

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

Delete a project

Delete a specific project

 

Header Auth

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

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

ID of the project you want to delete

 

Add resources to a project

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

 

Header Auth

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

You couldn't be authenticated

Try the API to see results

Body Params

resource_id
string
required

ID of the resource you want to add to the project

 

Set resources on a project

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

 

Header Auth

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

You couldn't be authenticated

Try the API to see results
 

Updates the resources connected to a project.

Replaces array

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

Remove a resource from a project

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

 

Header Auth

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

You couldn't be authenticated

Try the API to see results

Path Params

project_id
string
required

ID of the project

resource_id
string
required

ID of the resource you want to remove

 

Remove a specific resource from a project

Get resources for a project

 

Header Auth

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

You couldn't be authenticated

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