Calendar App

This document describes the Calendar App authentication and API reference.

Authorization flow

1. Create a private key

Generate and download the private key on the detail of Calendar App page, only the paired public key is stored on the TimeTree server. Check the fingerprint of the downloaded pem file with the following command.

$ chmod 600 PATH_TO_PEM_FILE
$ ssh-keygen -ylf PATH_TO_PEM_FILE -E md5

2. Getting the installation_id

When the Calendar App is linked by the user, a installation_id associated with the linked calendar is generated. An access token can be issued for each installation_id.

There are two ways to notify installation_id from the TimeTree server:

  • Notification via Webhook (Required)
  • Redirect by setup URL (Optional)

Notification via webhook

When the Calendar App is linked by the user, TimeTree will notify installation_id in an HTTP POST request. The request Body will be JSON in the following format.

{
  action: "created",
  installation: {
    id: "${INSTALLATION_ID}",
    application: {
      id: "${CALENDAR_APP_ID}",
      name: "${CALENDAR_APP_NAME}",
      icon_url: "${CALENDAR_APP_ICON}",
    },
    scopes: ["${SCOPES}"],
    updated_at: "2020-03-01T00:00:00Z",
    created_at: "2020-03-01T00:00:00Z"
  }
}
Validation of Webhook requests with Webhook Secret

The Webhook Secret can be used to validate Webhooks. You can verify that the webhook came from the TimeTree server by validating the webhook request. TimeTree uses Secret to hash the request body and embed it in the X-Timetree-Signature header when sending the Webhook.

X-Timetree-Signature: sha1=${PAYLOAD_SHA1_SIGNATURE}
How to verify the signature(Ruby)
require 'openssl'

signature = OpenSSL::HMAC.hexdigest('SHA1', YOUR_SECRET, PAYLOAD_JSON_STR.to_json)
put 'valid' if signature == X_TIMETREE_SIGNATURE.tr('sha1=', '')

Redirect by setup URL

If you set the setup URL, the Calendar App will redirect to the following URL after being linked by the user.

{setup_url}?installation_id={installation_id}

3. Generating a JWT and getting an access token

When the Calendar App accesses the TimeTree API, it needs to get a short-lived access token using the JWT generated using the Calendar App ID and the private key downloaded above. See Get an Access Token for more information on the request.

Sample code to generate a JWT(Ruby)

require 'openssl'
require 'jwt' # gem install jwt

# Private key contents
private_pem = File.read(YOUR_PATH_TO_PEM)
private_key = OpenSSL::PKey::RSA.new(private_pem)

# Generate payload
payload = {
  iat: Time.now.to_i, # issued at time
  exp: Time.now.to_i + (10 * 60), # JWT expiration time (10 minute maximum)
  iss: YOUR_CALENDAR_APP_ID
}

jwt = JWT.encode(payload, private_key, "RS256")
puts jwt

TimeTree notify you of the deactivated installation_id via webhook when a user unlinks your Calendar App. Please remove the installation_id properly to avoid sending unnecessary API requests to the obsoleteinstallation_id.

TimeTree sends an HTTP POST request when it is unlinked. The request Body is JSON in the following format.

{
  action: "deleted",
  installation: {
    id: "${INSTALLATION_ID}",
    application: {
      id: "${CALENDAR_APP_ID}",
      name: "${CALENDAR_APP_NAME}",
      icon_url: "${CALENDAR_APP_ICON}",
    },
    scopes: ["${SCOPES}"],
    updated_at: "2020-03-01T00:00:00Z",
    created_at: "2020-03-01T00:00:00Z"
  }
}

API reference

Get an access token

Get an access token for the installation_id.

Endpoint

POST /installations/:installation_id/access_tokens

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header JWT signed with a private key.
installation_id integer path ID corresponding to the linkage acquired by the setup URL or Webhook

Scope

None

cURL Example

$ curl \
  -X POST
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $JWT" \
  https://timetreeapis.com/installations/12345/access_tokens

Response Example

HTTP/1.1 200 OK
{
  "access_token": "ACCESS_TOKEN",
  "expire_at": 1558583443, // unix timestamp
  "token_type": "Bearer"
}

Get a calendar

Get the information of the calendar.

Endpoint

GET /calendar

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
include string query Includes association's object in the response. Separated by ,. Only supports labels and members.

Scope

Read:Calendar

cURL Example

$ curl \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar?include=labels,members

Response Example

HTTP/1.1 200 OK
{
  "data": {
    "id":  "1234",
    "type": "calendar",
    "attributes": {
      "name": "Some Calendar",
      "description": "Calendar description",
      "color": "#2ecc87",
      "order": 0,
      "image_url": "https://attachments.timetreeapp.com/path/to/image.png",
      "created_at": "2019-04-01T12:34:56.000Z"
    },
    "relationships": {
      "labels": {
        "data": [
          { "id": "1234,1", "type": "label" },
          { "id": "1234,2", "type": "label" },
          { "id": "1234,3", "type": "label" },
          { "id": "1234,4", "type": "label" },
          { "id": "1234,5", "type": "label" },
          { "id": "1234,6", "type": "label" },
          { "id": "1234,7", "type": "label" },
          { "id": "1234,8", "type": "label" },
          { "id": "1234,9", "type": "label" },
          { "id": "1234,10", "type": "label" }
        ]
      },
      "members": {
        "data": [
          { "id": "1234,12345", "type": "user" },
          { "id": "1234,23456", "type": "user" }
        ]
      }
    }
  },
  "included": [
    {
      "id": "1234,1",
      "type": "label",
      "attributes": {
        "name": "label title(empty if default)",
        "color": "#2ecc87"
      }
    },
    // ...
    {
      "id": "1234,12345",
      "type": "user",
      "attributes": {
        "name": "User1",
        "description": "blah blah blah",
        "image_url": "https://attachments.timetreeapp.com/path/to/image.png"
      }
    },
    // ...
  ]
}

List members

Get the member information of the calendar.

Endpoint

GET /calendar/members

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token

Scope

Read:Calendar Member

cURL Example

$ curl \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/members

Response Example

HTTP/1.1 200 OK
{
  "data": [
    {
      "id": "1234,12345",
      "type": "user",
      "attributes": {
        "name": "User1",
        "description": "blah blah blah",
        "image_url": "https://attachments.timetreeapp.com/path/to/image.png"
      }
    },
    {
      "id": "1234,56789",
      "type": "user",
      "attributes": {
        "name": "User2",
        "description": "Foo Bar",
        "image_url": "https://attachments.timetreeapp.com/path/to/anothor_image.png"
      }
    },
    // ...
  ]
}

List upcoming events

Get information on the events after the day of the request for the specified calendar.

Endpoint

GET /calendar/upcoming_events

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
timezone string query Timezone. Used for all day event. This does not change response's timezone. Default is UTC.
days string query The number of days to get. A range from 1 to 7 can be specified. Default is 1.
include string query Includes association's object in the response. Separated by ,. Only supports creator, label and attendees.

Scope

Read:Event

cURL Example

$ curl \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/upcoming_events?timezone=Asia/Tokyo&days=3&include=creator,label,attendees

Response Example

HTTP/1.1 200 OK
{
  "data": [
    {
      "id": "c9c8e0fd66c34505a876d88cb4bb3b2a",
      "type": "event",
      "attributes": {
        "category": "schedule",
        "title": "Event title",
        "all_day": false,
        "start_at": "2019-03-18T09:00:00.000Z",
        "start_timezone": "UTC",
        "end_at": "2019-03-18T10:00:00.000Z",
        "end_timezone": "UTC",
        "recurrence": [],
        "description": "blah blah blah",
        "location": "Tokyo",
        "url": "https://example.com",
        "updated_at": "2019-03-18T09:53:33.123Z",
        "created_at": "2019-03-18T09:53:33.123Z"
      },
      "relationships": {
        "creator": {
          "data": {
            "id": "1234,12345",
            "type": "user"
          }
        },
        "label": {
          "data": {
            "id": "1234,1",
            "type": "label"
          }
        },
        "attendees": {
          "data": [
            { "id": "1234,12345", "type": "user" },
            { "id": "1234,56789", "type": "user" }
          ]
        }
      },
      // ...
    }
  ]
}

Get an event

Get an event information.

Endpoint

GET /calendar/events/:event_id

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
event_id string path Event ID
include string query Includes association's object in the response. Separated by ,. Only supports creator, label and attendees.

Scope

Read:Event

cURL Example

$ curl \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/events/c9c8e0fd66c34505a876d88cb4bb3b2a?include=creator,label,attendees

Response Example

HTTP/1.1 200 OK
{
  "data": {
    "id": "c9c8e0fd66c34505a876d88cb4bb3b2a",
    "type": "event",
    "attributes": {
      "category": "schedule",
      "title": "Event title",
      "all_day": false,
      "start_at": "2019-03-18T09:00:00.000Z",
      "start_timezone": "UTC",
      "end_at": "2019-03-18T10:00:00.000Z",
      "end_timezone": "UTC",
      "recurrence": [],
      "description": "blah blah blah",
      "location": "Tokyo",
      "url": "https://example.com",
      "updated_at": "2019-03-18T09:53:33.123Z",
      "created_at": "2019-03-18T09:53:33.123Z"
    },
    "relationships": {
      "creator": {
        "data": {
          "id": "1234,12345",
          "type": "user"
        }
      },
      "label": {
        "data": {
          "id": "1234,1",
          "type": "label"
        }
      },
      "attendees": {
        "data": [
          { "id": "1234,12345", "type": "user" },
          { "id": "1234,56789", "type": "user" }
        ]
      }
    }
  }
}

Create an event

Create an event to the calendar.

Endpoint

POST /calendar/events

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
data:attributes:title string body Required Event's title. Up to 50 characters.
data:attributes:category string body Required Specify schedule or keep.
data:attributes:all_day boolean body All day event flag. schedule: Required、keep: Optional
data:attributes:start_at string body Start datetime(ISO8601). If all day event, you must set time to 00:00:00. schedule: Required、keep: Optional
data:attributes:start_timezone string body Start timezone
data:attributes:end_at string body End datetime(ISO8601). If all day event, you must set time to 00:00:00. You must set after start_at. schedule: Required、keep: Optional
data:attributes:end_timezone string body End timezone
data:attributes:description string body Description(note). Up to 10000 characters.
data:attributes:location string body Location. Up to 100 characters.
data:attributes:url string body URL
data:relationships:attendees:data[]:id string body Attendee's user id
data:relationships:attendees:data[]:type string body user only. If you have data:relationships:attendees:data[]:id, required

Scope

Write:Event

cURL Example

$ curl \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/events \
  -d '{
    "data": {
      "attributes": {
        "category": "schedule",
        "title": "Event title",
        "all_day": false,
        "start_at": "2019-03-18T09:00:00.000Z",
        "start_timezone": "UTC",
        "end_at": "2019-03-18T10:00:00.000Z",
        "end_timezone": "UTC",
        "description": "blah blah blah",
        "location": "Tokyo",
        "url": "https://example.com"
      },
      "relationships": {
        "label": {
          "data": {
            "id": "1234,1",
            "type": "label"
          }
        },
        "attendees": {
          "data": [
            { "id": "1234,12345", "type": "user" },
            { "id": "1234,56789", "type": "user" }
          ]
        }
      }
    }
  }'

Response Example

HTTP/1.1 201 Created
{
  "data": {
    "id": "c9c8e0fd66c34505a876d88cb4bb3b2a",
    "type": "event",
    "attributes": {
      "category": "schedule",
      "title": "Event title",
      "all_day": false,
      "start_at": "2019-03-18T09:00:00.000Z",
      "start_timezone": "UTC",
      "end_at": "2019-03-18T10:00:00.000Z",
      "end_timezone": "UTC",
      "recurrence": [],
      "description": "blah blah blah",
      "location": "Tokyo",
      "url": "https://example.com",
      "updated_at": "2019-03-18T09:53:33.123Z",
      "created_at": "2019-03-18T09:53:33.123Z"
    },
    "relationships": {
      "creator": {
        "data": {
          "id": "1234,12345",
          "type": "user"
        }
      },
      "label": {
        "data": {
          "id": "1234,1",
          "type": "label"
        }
      },
      "attendees": {
        "data": [
          { "id": "1234,12345", "type": "user" },
          { "id": "1234,56789", "type": "user" }
        ]
      }
    }
  }
}

Update an event

Update an event.

Endpoint

PUT /calendar/events/:event_id

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
event_id string path Event ID
data:attributes:title string body Required Event's title. Up to 50 characters.
data:attributes:category string body Required Specify schedule or keep.
data:attributes:all_day boolean body All day event flag. schedule: Required、keep: Optional
data:attributes:start_at string body Start datetime(ISO8601). If all day event, you must set time to 00:00:00. schedule: Required、keep: Optional
data:attributes:start_timezone string body Start timezone
data:attributes:end_at string body End datetime(ISO8601). If all day event, you must set time to 00:00:00. You must set after start_at. schedule: Required、keep: Optional
data:attributes:end_timezone string body End timezone
data:attributes:description string body Description(note). Up to 10000 characters.
data:attributes:location string body Location. Up to 100 characters.
data:attributes:url string body URL
data:relationships:attendees:data[]:id string body Attendee's user id
data:relationships:attendees:data[]:type string body user only. If you have data:relationships:attendees:data[]:id, required

Scope

Write:Event

cURL Example

$ curl \
  -X PUT \
  -H "Content-Type: application/json" \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/events/c9c8e0fd66c34505a876d88cb4bb3b2a \
  -d '{
    "data": {
      "attributes": {
        "category": "schedule",
        "title": "Event title",
        "all_day": false,
        "start_at": "2019-03-18T09:00:00.000Z",
        "start_timezone": "UTC",
        "end_at": "2019-03-18T10:00:00.000Z",
        "end_timezone": "UTC",
        "description": "blah blah blah",
        "location": "Tokyo",
        "url": "https://example.com"
      },
      "relationships": {
        "label": {
          "data": {
            "id": "1234,1",
            "type": "label"
          }
        },
        "attendees": {
          "data": [
            { "id": "1234,12345", "type": "user" },
            { "id": "1234,56789", "type": "user" }
          ]
        }
      }
    }
  }'

Response Example

HTTP/1.1 200 OK
{
  "data": {
    "type": "event",
    "id": "c9c8e0fd66c34505a876d88cb4bb3b2a",
    "attributes": {
      "category": "schedule",
      "title": "Event title",
      "all_day": false,
      "start_at": "2019-03-18T09:00:00.000Z",
      "start_timezone": "UTC",
      "end_at": "2019-03-18T10:00:00.000Z",
      "end_timezone": "UTC",
      "recurrence": [],
      "description": "blah blah blah",
      "location": "Tokyo",
      "url": "https://example.com",
      "updated_at": "2019-03-18T09:53:33.123Z",
      "created_at": "2019-03-18T09:53:33.123Z"
    },
    "relationships": {
      "author": {
        "data": {
          "id": "1234,12345",
          "type": "user"
        }
      },
      "label": {
        "data": {
          "id": "1234,1",
          "type": "label"
        }
      },
      "attendees": {
        "data": [
          { "id": "12345", "type": "user" },
          { "id": "56789", "type": "user" }
        ]
      }
    }
  }
}

Delete an event

Delete an event.

Endpoint

DELETE /calendar/events/:event_id

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
event_id string path Event ID

Scope

Write:Event

cURL Example

$ curl \
  -X DELETE \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/events/c9c8e0fd66c34505a876d88cb4bb3b2a

Response Example

HTTP/1.1 204 No Content

Create a comment

Creates comment to an event.

Endpoint

POST /calendar/events/:event_id/activities

Parameters

Name Type In Description
accept string header application/vnd.timetree.v1+json recommended
authorization string header Obtained access token
event_id string path Event ID
data:attributes:content string body Required Comment text. Up to 1000 characters.

Scope

Write:Comment

cURL Example

$ curl \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://timetreeapis.com/calendar/events/c9c8e0fd66c34505a876d88cb4bb3b2a/activities \
  -d '{
    "data": {
      "attributes": {
        "content": "This is comment"
      }
    }
  }'

Response Example

HTTP/1.1 201 Created
{
  "data": {
    "id": "5fde58f529bf4359b6cc15523ed86965",
    "type": "activity",
    "attributes": {
      "content": "This is comment",
      "updated_at": "2019-04-01T12:34:56.000Z",
      "created_at": "2019-04-01T12:34:56.000Z"
    }
  }
}