NAV
php shell

Teamup API Overview

The teamup.com API allows basic access to sub-calendars and events.

The API endpoints described here are the only ones we currently officially support and intend on maintaining backwards compatible. As such if you use any other URL you have to understand you are doing so at your own risk.

If the API endpoints described here are not sufficient for your requirements, please get in touch with us and we will be happy to discuss further integration points.

Usage of the API is included in the subscription plans offered for Teamup. There is no additional fee. We only ask you to register your application by requesting an API key for free. This provides us with a means to contact you, should the need arise to do so.

General API Guidelines

Please also take a look at the API Usage Best Practices.

Querying the Teamup API

API Key

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/events');

print $result->getStatusCode();
// "200"

print $result->getHeader('content-type');
// 'application/json'

print $result->getBody();
// {"events":[ ... ]}
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events" \
    -H "Teamup-Token: API_KEY"

Every request to the API must include an API key in a request header.

We ask you to register your application by requesting an API key for free. This provides us with a means to inform you about changes to the API or contact you, should the need arise to do so.

Calendar Key

Almost all API requests require a calendar key as part of the request URL. For example, to read a list of events the following API request is used:

GET /{calendarKey}/events

{calendarKey} addresses a specific calendar. One calendar can have many calendar keys and each calendar key has associated permissions, for example read-only, modify or administration. For each API endpoint you find the needed permission in the documentation of that endpoint.

Calendar keys are managed using the Web-based calendar settings application. Look for the Sharing tab.

API Clients

The API can be queried using any HTTP client. Our documentation provides PHP and cURL examples. The PHP examples use the Guzzle library (version 6). You can install it in your project using Composer by running:

composer require 'guzzlehttp/guzzle:^6.0'

Testing your API key

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->get('https://api.teamup.com/check-access');

if ($result->isSuccessful()) {
    print 'Your API key works!';
} else {
    print 'API key test failed: ' . $result->getBody();
}
curl "https://api.teamup.com/check-access" \
    -H 'Teamup-Token: API_KEY'

Expected response:

200 OK
{
    "access": "ok"
}

This endpoint lets you check if your API key is valid and you are submitting it as expected.

HTTP Request

GET /check-access

Querying password-protected calendars

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => [
    'Teamup-Token' => 'API_KEY',
    'Teamup-Password' => 'demopassword'
]);

$result = $client->get('https://api.teamup.com/kscb1caefc73e9f0a8/events');

print $result->getStatusCode();
// "200"

print $result->getHeader('content-type');
// 'application/json'

print $result->getBody();
// {"events":[ ... ]}
curl "https://api.teamup.com/kscb1caefc73e9f0a8/subcalendars" \
    -H 'Teamup-Token: API_KEY' -H 'Teamup-Password: demopassword'

For password-protected calendars, you must send a custom Teamup-Password header that has the password as value.

Querying the API using cURL on Windows

If you use the cURL samples in Windows’s cmd.exe, and want to POST JSON data, you will have to escape the JSON text. For example use curl ... -d "{""json"": ""data""}" with all the double quotes appearing twice within the string. On Linux or using cygwin cURL builds this is not an issue as you can quote using single quotes (') to avoid having to escape the double quotes.

The other thing to take into account is that by default your cURL might not come with an SSL CABundle, which prevents it from making secure connections to us, and it will warn you about a self-signed certificate. The solution is to download a CA bundle and save it next to curl.exe, with the file name curl-ca-bundle.crt (don’t forget to change the extension from .pem). This will give cURL the knowledge about root certificate authorities, which will allow it to validate our SSL certificate against it. You should ideally keep this file updated reasonably often to make sure any revoked certificates are removed and new ones added.

Querying the API via JavaScript / CORS

Example:

// Creates a CORS request in a cross-browser manner
function createCORSRequest(method, url) {
    var apiKey = 'API_KEY';
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr) {
        // XHR for Chrome/Firefox/Opera/Safari/IE10+.
        xhr.open(method, url, true);
        xhr.setRequestHeader('Teamup-Token', apiKey);
    } else if (typeof XDomainRequest != "undefined") {
        // XDomainRequest for IE8/IE9.
        xhr = new XDomainRequest();
        // XDomainRequest does not support querying HTTPS from HTTP pages
        if (window.location.protocol === 'http:') {
            url = url.replace('https://', 'http://');
        }
        if (-1 === ['GET', 'POST'].indexOf(method)) {
            alert('XDomainRequest only supports GET and POST methods');
            return;
        }
        if (-1 === url.indexOf('?')) {
            url += '?_teamup_token=' + apiKey;
        } else {
            url += '&_teamup_token=' + apiKey;
        }
        xhr.open(method, url);
    } else {
        // CORS not supported.
        xhr = null;
    }
    return xhr;
}

// Sends the actual CORS request.
function makeCorsRequest(url, successCallback, errorCallback) {
    var xhr = createCORSRequest('GET', url);
    if (!xhr) {
        alert('CORS not supported');
        return;
    }

    // Response handlers.
    xhr.onload = function (xhr) {
        if (xhr.target.status < 400) {
            if (successCallback) successCallback(xhr.target);
        } else if (errorCallback) {
            errorCallback(xhr.target);
        }
    };
    xhr.onerror = function (xhr) {
        if (errorCallback) {
            errorCallback(xhr.target);
        }
    };

    xhr.send();
}

// Send a GET request for all events in a date range
makeCorsRequest(
    'https://api.teamup.com/ks73ad7816e7a61b3a/events?startDate=2015-06-01&endDate=2015-06-05',
    function(xhr) {
        var data = JSON.parse(xhr.responseText);
        alert('Successfully Received: ' + JSON.stringify(data));
    },
    function(xhr) {
        var data = JSON.parse(xhr.responseText);
        alert('Request failed with code '+ xhr.status +': ' + JSON.stringify(data));
    }
);

The Teamup API supports Cross-Origin Resource Sharing requests. This is the preferred way and is widely supported across all browsers.

If you do ajax requests with jQuery for example it will use CORS by default and everything should work out of the box. If you wish to do it with pure JS you can use the code snippet on the right to make it work across browsers.

Note that IE8 and IE9 only support XDomainRequest and not the full CORS specification. If you need to support those versions, be mindful of the following limitations:

The code above takes care of most of these for you but supporting IE8/9 will still restrict your usage. To use the full API you can write a simple server-side script to proxy your requests to the Teamup API via your server and then use regular XMLHttpRequest calls.

Date and Time Formats

All parameters and properties of type date and/or time follow the ISO-8601 standard on date and time formats.

Example Description
2015-01-31 Date only
2015-01-31T10:00:00 Date and time, default timezone
2015-01-31T10:00:00Z Date and time, timezone UTC
2015-01-31T10:00:00-05:00 Date and time, timezone -05:00

Default Timezone

If timezone is not specified, then the default timezone is assumed. The default timezone is:

  1. The timezone defined by the tz query parameter or
  2. The calendar’s default timezone as specified in the calendar’s configuration

Global Query Parameters

The following query parameters are available for all API end points:

Parameter Type Default Description
tz string Calendar timezone The request timezone. Supported timezones include: UTC, America/New_York and equivalent (see TZ database timezones for a full list). Note that this parameter is only respected by the server if the calendar is configured to allow users changing the timezone. See Settings -> Date & Time of your calendar.
lang string Calendar language The language to use in responses. Currently supported values are en, en_GB, fr, de, es, hu.

Configuration

Read Configuration

Example:

<?php

$client = new GuzzleHttp\Client(['headers': {'Teamup-Token': 'API_KEY']]);
$result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/configuration');

print $result->getBody();
curl "https://api.teamup.com/ks73ad7816e7a61b3a/configuration" \
    -H 'Teamup-Token: API_KEY'

Expected response:

200 OK
{
  "configuration": {
    "general_settings": {
      "admin_email": "support@teamup.com",
      "language": "en",
      "control_panel_default_state": "visible",
      "onetomany_enabled": false,
      "user_signup_enabled": true,
      "icsfeeds_enabled": true,
      "about": "<p>This is a demo calendar</p>",
      "about_enabled": true,
      "about_title": "About"
    },
    "calendar_views": {
      "default_view": "MW",
      "show_day_view": true,
      "show_week_view": true,
      "show_multiday_view": true,
      "show_multiweek_view": true,
      "show_month_view": true,
      "show_agenda_view": false,
      "show_list_view": true,
      "show_scheduler_view": true,
      "show_year_view": true,
      "week_hide_weekend": true,
      "multiweek_number_of_weeks": 4,
      "multiday_number_of_days": 3,
      "agenda_date_range": "3months",
      "agenda_show_details": false,
      "list_date_range": "3months",
      "list_group_by": "month",
      "list_show_details": true,
      "year_number_of_months": 12
    },
    "date_time": {
      "tz_dynamic": true,
      "tz": "Europe/London",
      "tz_show": true,
      "time_range_start": 6,
      "time_range_end": 24,
      "start_date_type": "current",
      "start_date": "2015-01-01",
      "start_date_pattern": "y1",
      "week_start": 0
    },
    "identity": {
      "title": "Team Absence & Travel Planner",
      "customize": false,
      "show_custom_logo": true,
      "logo_uri": "//teamup.com/app/customlogo/key/ks73ad7816e7a61b3a",
      "header_background_color": "#FFFFFF",
      "header_font_color": "#283842"
    },
    "link": {
      "name": "Administrator",
      "key": "ks73ad7816e7a61b3a"
    },
    "features": {
      "calendar_limit": 10,
      "history": 12,
      "daily_agenda": false,
      "file_upload": false,
      "notification_for_past": false,
      "import_feed_frequency": [
        43200,
        10080,
        720
      ]
    }
  }
}

This endpoint can be used to retrieve the configuration of a calendar.

HTTP Request

GET /{calendarKey}/configuration

Events

Event Data Structure

The following table documents the attributes of a calendar event. Please note that some event attributes are read-only while others are update-only. Read-only attributes are returned in server responses but do not need to be submitted in requests. Update-only attributes need to be submitted in requests but are not returned in server responses. The notes below the table give more details.

Parameter Type Default Description
id string generated Event id
remote_id* string/null null Unique id of event in a third party system, (optional)
series_id int/null generated (read-only) Id of recurring event series to which this event belongs (recurring events only)
subcalendar_ids array of int - A list of ids of sub-calendars to which event is assigned
subcalendar_id* int - (DEPRECATED) Id of sub-calendar to which event is assigned
start_dt date - Event start date in ISO-8601 format
end_dt date - Event end date in ISO-8601 format
all_day bool - Whether the event spans all day or not
title string "" Event title, 0 to 255 characters
who string "" Event attendee information, 0 to 255 characters
location string "" Event location, 0 to 255 characters
notes* string "" Event notes, 0 to 65535 characters
rrule* string "" Recurrence rule (recurring events only)
redit* string - (update-only) The edit mode when updating recurring events (recurring events only)
ristart_dt* date generated The recurrence instance start date (recurring events only)
rsstart_dt* date generated (read-only) The start date of the recurring series of events to which this event instance belongs (recurring events only)
tz* string/null request tz Timezone for which the recurrence rule is evaluated (recurring events only)
version* string generated The event version
readonly* bool generated (read-only) Whether the event can be modified
creation_dt date generated (read-only) Event creation date in ISO-8601 format
update_dt date/null generated (read-only) Event last update date in ISO-8601 format

Notes

Get Events Collection

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/events?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD');

print $result->getBody();
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD" \
    -H 'Teamup-Token: API_KEY'

Expected response:

200 OK
{
    "events": [
        {
            "id": "123",
            "remote_id": null,
            "series_id": null,
            "subcalendar_id": [730624],
            "subcalendar_id": 730624,
            "start_dt": "2015-06-17T06:00:00-0400",
            "end_dt": "2015-06-17T07:00:00-0400",
            "all_day": false,
            "title": "Demo Event",
            "who": "",
            "location": "",
            "notes": "",
            "rrule": "",
            "ristart_dt": null,
            "rsstart_dt": null,
            "tz": null,
            "version": "556db1f949aa6",
            "readonly": false,
            "creation_dt": "2015-06-02T13:39:05+0000",
            "update_dt": null,
        }
    ]
}

Retrieve a list of events for a specified time range.

HTTP Request

GET /{calendarKey}/events

Query Parameters

Parameter Type Default Description
startDate date now The start of the date range to list events from, in YYYY-MM-DD format
endDate date now +1 day The end of the date range to list events from (inclusive), in YYYY-MM-DD format
format string html Can be used to request the format of the event notes in the response. Supported values are html, markdown or both (array). To request both formats, use this syntax: ?format[]=html&format[]=markdown.
modifiedSince timestamp - If parameter is present, only events modified, created or deleted since the given timestamp (unix timestamp format) are returned.

Notes

Get a Specific Event

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/events/11449078');

print $result->getBody();
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events/11449078" \
    -H 'Teamup-Token: API_KEY'

Expected response:

200 OK
{
    "event": {
        "id": "11449078",
        "subcalendar_id": 893615,
        "start_dt": "2015-06-01T00:00:00+0000",
        "end_dt": "2015-06-01T23:59:00+0000",
        "all_day": true,
        "rrule": "",
        "title": "Demo Event 1 - All Day",
        "who": "",
        "location": "",
        "notes": "",
        "version": "55817b2954ae4",
        "ristart_dt": null,
        "creation_dt": "2015-06-17T13:50:33+0000",
        "update_dt": null,
        "readonly": false
    }
}

This endpoint retrieves a specific event.

HTTP Request

GET /{calendarKey}/events/{eventId}

Query Parameters

Parameter Type Default Description
format string html Can be used to request the format of the event notes in the response. Supported values are html, markdown or both (array). To request both formats, use this syntax: ?format[]=html&format[]=markdown.

Create a new Event

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->post('https://api.teamup.com/ks73ad7816e7a61b3a/events', [
    'json' => [
        "subcalendar_id" => 730624,
        "start_dt" => "2015-06-17T06:00:00-0400",
        "end_dt" => "2015-06-17T07:00:00-0400",
        "all_day" => false,
        "rrule" => "",
        "title" => "Demo Event",
        "who" => "",
        "location" => "",
        "notes" => "",
    ]
]);
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events" -XPOST \
    -H 'Teamup-Token: API_KEY' \
    -H 'Content-type:application/json' \
    --data '{
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "Demo Event",
        "who": "",
        "location": "",
        "notes": ""
    }'

Expected response:

201 Created
Location: /{calendarKey}/events/{eventId}
{
    "event": {
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "Demo Event",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556db1f949aa6",
        "ristart_dt": null,
        "creation_dt": "2015-06-02T13:39:05+0000",
        "update_dt": null,
        "readonly": false
    }
}

This API endpoint can be used to create a new calendar event.

HTTP Request

POST /{calendarKey}/events

Query Parameters

Parameter Type Default Description
format string html Can be used to request the format of the event notes in the response. Supported values are html, markdown or both (array). To request both formats, use this syntax: ?format[]=html&format[]=markdown.
inputFormat string html By default, the event notes in the request are expected to be html formatted. If this is not the case, this parameter can be used to declare the format. Supported values are htmland markdown.

Update an Event

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->put('https://api.teamup.com/ks73ad7816e7a61b3a/events/123', [
    'json' => [
        "id" => "123",
        "subcalendar_id" => 730624,
        "start_dt" => "2015-06-17T06:00:00-0400",
        "end_dt" => "2015-06-17T07:00:00-0400",
        "all_day" => false,
        "rrule" => "",
        "title" => "New Title",
        "who" => "",
        "location" => "",
        "notes" => "",
        "version" => "556db1f949aa6",
        "redit" => null,
        "ristart_dt" => null,
    ]
]);
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events/123" -XPUT\
    -H 'Teamup-Token: API_KEY' \
    -H 'Content-type:application/json' \
    --data '{
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "New Title",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556db1f949aa6",
        "redit": null,
        "ristart_dt": null
    }'

Expected response:

200 OK
{
    "event": {
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "New Title",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556dd350bf702",
        "ristart_dt": null,
        "creation_dt": "2015-06-02T13:39:05+0000",
        "update_dt": null,
        "readonly": false
    }
}

This API endpoint can be used to update an existing event.

HTTP Request

PUT /{calendarKey}/events/{eventId}

Query Parameters

Parameter Type Default Description
format string html Can be used to request the format of the event notes in the response. Supported values are html, markdown or both (array). To request both formats, use this syntax: ?format[]=html&format[]=markdown.
inputFormat string html By default, the event notes in the request are expected to be html formatted. If this is not the case, this parameter can be used to declare the format. Supported values are htmland markdown.

Note on version conflicts

The event attribute version represents the version of an event. This attribute is updated by the server whenever an event is changed. It implements a soft-locking mechanism to prevent multiple users from overwriting each others’ changes. A request to update an event is only accepted if the given version is equal to the latest value of this attribute in the calendar database.

If an event carries an old version, then an update request is rejected with the error id: event_validation_conflict. In that case, before the event can be updated it must be read from the server in order to obtain the latest version. Any modifications should then be applied to it again before doing a new update.

Note on recurring events

When updating a recurring event, event attribute redit can be used to specify how the update will be applied. Supported value are:

Delete an Event

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->delete('https://api.teamup.com/ks73ad7816e7a61b3a/events/123', [
    'json' => [
        "id" => "123",
        "subcalendar_id" => 730624,
        "start_dt" => "2015-06-17T06:00:00-0400",
        "end_dt" => "2015-06-17T07:00:00-0400",
        "all_day" => false,
        "rrule" => "",
        "title" => "New Title",
        "who" => "",
        "location" => "",
        "notes" => "",
        "version" => "556db1f949aa6",
        "redit" => null,
        "ristart_dt" => null,
    ]
]);
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events/123" -XDELETE \
    -H 'Teamup-Token: API_KEY' \
    -H 'Content-type:application/json' \
    --data '{
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "New Title",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556db1f949aa6",
        "redit": null,
        "ristart_dt": null
    }'

Expected response:

204 No Content

This endpoint lets you delete an event.

HTTP Request

DELETE /{calendarKey}/events/{eventId}

Note on recurring events

When deleting a recurring event, event attribute redit can be used to specify how the delete operations will be applied. Supported value are:

Sub-Calendars

A calendar has one to many sub-calendars. Sub-calendars represent categories of events. Events are always associated with at least one sub-calendar. Each sub-calendar has a color assigned which is used to visualize the sub-calendar and events assigned to it in the user interfaces.

Sub-Calendar Data Structure

A Sub-Calendar object has the following attributes:

Parameter Type Default Description
id int generated (read-only) Sub-calendar id
name string - Sub-calendar name, 1 to 100 characters. Sub-calendar names must be unique.
active bool true Whether the sub-calendar is enabled or not
color int/string 17 Color id. An integer between 1 and 48 from the list of predefined colors. Use of custom colors (e.g. #ABCD12) is not in use yet but might be eventually so you should handle them to be future-proof.
overlap bool true Whether the sub-calendar can have multiple events overlapping each other
creation_dt date generated (read-only) Event creation date
update_dt date/null generated (read-only) Event last update date
readonly bool generated (read-only) Whether the sub-calendar can be written to. This is a calculated attribute. Its value depends on the permission of the calendar key used for the request.

Get Sub-Calendars Collection

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars');

print $result->getBody();
curl "http://api.teamup.com/ks73ad7816e7a61b3a/subcalendars" \
    -H 'Teamup-Token: API_KEY'

Expected response:

200 OK
{
    "subcalendars": [
        {
            "id": 730624,
            "name": "Calendar 1",
            "active": true,
            "color": 19,
            "overlap": true,
            "creation_dt": "2015-04-29T09:50:28+00:00",
            "update_dt": "2015-04-29T09:52:00+00:00",
            "readonly": false
        },
        {
            "id": 730625,
            "name": "Calendar 2",
            "active": true,
            "color": 3,
            "overlap": true,
            "creation_dt": "2015-04-29T09:50:29+00:00",
            "update_dt": "2015-04-29T09:52:02+00:00",
            "readonly": true
        }
    ]
}

This endpoint returns a list of all sub-calendars for the addressed calendar.

HTTP Request

GET /{calendarKey}/subcalendars

Query Parameters

None

Get a Specific Sub-Calendar

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/events/11449078');

print $result->getBody();
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events/11449078" \
    -H 'Teamup-Token: API_KEY'

Expected response:

200 OK
{
    "event": {
        "id": "11449078",
        "subcalendar_id": 893615,
        "start_dt": "2015-06-01T00:00:00+0000",
        "end_dt": "2015-06-01T23:59:00+0000",
        "all_day": true,
        "rrule": "",
        "title": "Demo Event 1 - All Day",
        "who": "",
        "location": "",
        "notes": "",
        "version": "55817b2954ae4",
        "ristart_dt": null,
        "creation_dt": "2015-06-17T13:50:33+0000",
        "update_dt": null,
        "readonly": false
    }
}

This endpoint retrieves a specific sub-calendar.

HTTP Request

GET /{calendarKey}/subcalendars/{subCalendarId}

Query Parameters

None

Create a new Sub-Calendar

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->post('https://api.teamup.com/ks73ad7816e7a61b3a/events', [
    'json' => [
        "subcalendar_id" => 730624,
        "start_dt" => "2015-06-17T06:00:00-0400",
        "end_dt" => "2015-06-17T07:00:00-0400",
        "all_day" => false,
        "rrule" => "",
        "title" => "Demo Event",
        "who" => "",
        "location" => "",
        "notes" => "",
    ]
]);
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events" -XPOST \
    -H 'Teamup-Token: API_KEY' \
    -H 'Content-type:application/json' \
    --data '{
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "Demo Event",
        "who": "",
        "location": "",
        "notes": ""
    }'

Expected response:

201 Created
Location: /{calendarKey}/events/{eventId}
{
    "event": {
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "Demo Event",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556db1f949aa6",
        "ristart_dt": null,
        "creation_dt": "2015-06-02T13:39:05+0000",
        "update_dt": null,
        "readonly": false
    }
}

This API endpoint can be used to create a new sub-calendar.

HTTP Request

POST /{calendarKey}/subcalendars

Query Parameters

None

Update a Sub-Calendar

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->put('https://api.teamup.com/ks73ad7816e7a61b3a/events/123', [
    'json' => [
        "id" => "123",
        "subcalendar_id" => 730624,
        "start_dt" => "2015-06-17T06:00:00-0400",
        "end_dt" => "2015-06-17T07:00:00-0400",
        "all_day" => false,
        "rrule" => "",
        "title" => "New Title",
        "who" => "",
        "location" => "",
        "notes" => "",
        "version" => "556db1f949aa6",
        "redit" => null,
        "ristart_dt" => null,
    ]
]);
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events/123" -XPUT\
    -H 'Teamup-Token: API_KEY' \
    -H 'Content-type:application/json' \
    --data '{
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "New Title",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556db1f949aa6",
        "redit": null,
        "ristart_dt": null
    }'

Expected response:

200 OK
{
    "event": {
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "New Title",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556dd350bf702",
        "ristart_dt": null,
        "creation_dt": "2015-06-02T13:39:05+0000",
        "update_dt": null,
        "readonly": false
    }
}

This API endpoint can be used to update an existing sub-calendar.

HTTP Request

PUT /{calendarKey}/subcalendars/{subCalendarId}

Query Parameters

None

Delete a Sub-Calendar

Example:

<?php

$client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
$result = $client->delete('https://api.teamup.com/ks73ad7816e7a61b3a/events/123', [
    'json' => [
        "id" => "123",
        "subcalendar_id" => 730624,
        "start_dt" => "2015-06-17T06:00:00-0400",
        "end_dt" => "2015-06-17T07:00:00-0400",
        "all_day" => false,
        "rrule" => "",
        "title" => "New Title",
        "who" => "",
        "location" => "",
        "notes" => "",
        "version" => "556db1f949aa6",
        "redit" => null,
        "ristart_dt" => null,
    ]
]);
curl "https://api.teamup.com/ks73ad7816e7a61b3a/events/123" -XDELETE \
    -H 'Teamup-Token: API_KEY' \
    -H 'Content-type:application/json' \
    --data '{
        "id": "123",
        "subcalendar_id": 730624,
        "start_dt": "2015-06-17T06:00:00-0400",
        "end_dt": "2015-06-17T07:00:00-0400",
        "all_day": false,
        "rrule": "",
        "title": "New Title",
        "who": "",
        "location": "",
        "notes": "",
        "version": "556db1f949aa6",
        "redit": null,
        "ristart_dt": null
    }'

Expected response:

204 No Content

This endpoint lets you delete a sub-calendar.

HTTP Request

DELETE /{calendarKey}/subcalendars/{subCalendarId}

Sub-Calendar Colors

The following table lists all colors supported for sub-calendars.

Color ID Hex Color ID Hex
33 #553711 20 #133897
34 #724f22 19 #2951b9
35 #9c6013 18 #4e79e6
5 #ca7609 17 #668CB3
6 #f88015 21 #1a5173
7 #eda12a 22 #1a699c
8 #d5b816 23 #3694b7
36 #f6c811 24 #64b9d9
3 #a01a1a 28 #176413
37 #ce1212 27 #2e8f0c
2 #cf2424 26 #83ad47
1 #fa7166 25 #a8c67b
38 #b90f4b 29 #0f4c30
39 #da145b 30 #386651
40 #ec427e 31 #3ea987
41 #f5699a 32 #7bc3b5
12 #7a0f60 42 #5c1c1c
11 #9d3283 4 #7e3838
10 #bf53a4 43 #a55757
9 #e281ca 44 #c37070
13 #542382 45 #000000
14 #7742a9 46 #383838
15 #8763ca 47 #757575
16 #b586e2 48 #a3a3a3

Errors

The Teamup API uses the following error codes:

Error Code Meaning
400 Bad Request – Invalid request
401 Unauthorized – Accessing a password-protected resource without providing authentication
403 Forbidden – Invalid credentials to access the given resource
404 Not Found – Resource missing, not found or not visible by your request
405 Method Not Allowed – You tried to access a resource with an invalid method (i.e. GET instead of POST)
406 Not Acceptable – You requested a format that is not json
415 Unsupported Media Type – The server is refusing to service the request because the payload is in a format not supported. Make sure you have the headers Content-Type: application/json and Content-Encoding properly set.
500 Internal Server Error – Application error on our side, we will look into it but feel free to reach out to us with details.
503 Service Unavailable – We are temporarially offline for maintanance. Please try again later.

Error Response Format

Example generic 400 response

400 Bad Request
{
    "error": {
        "id": "bad_request",
        "title": "Invalid request",
        "message": "The request parameters were invalid."
    }
}

Example validation error on event creation

400 Bad Request
{
    "error": {
        "id": "validation_error",
        "title": "Invalid event data",
        "message": [
            "The event title is too long. The maximum length is 255 characters.",
            "The value of the <i>Who<\/i> field is too long. The maximum length is 255 characters."
        ]
    }
}

All API errors are returned in the format you can see on the right. The error id is a constant string that you can rely on not to change. The title and message are translated strings that can be used to display errors to end users.

The message can also be an array in case there are multiple errors, for example when creating an event you may get multiple validation errors, see the second block on the right.

The message may contain HTML and should be considered safe for XSS purposes, but you can also safely strip all tags before rendering it.

Error IDs

Here is a list of known error ids our API may return and a short explanation of what they mean.

Error ID HTTP Status Code Explanation
maintenance_active 503 The application is in maintenance mode.
unexpected_error 500 The application experienced an unexpected error.
auth_required 401 Authentication is required to access this calendar key, you must provide a Teamup-Password header.
no_permission 403 You do not have the permissions to do this, you may be using a readonly calendar key for example.
event_add_only_permission_expired 400 If you use an add-only calendar key, events created can not be updated via the API.
calendar_not_found 404 You use an invalid calendar key.
event_not_found 404 The event id was not found.
event_overlapping 400 You tried to create an event conflicting with an existing event on a sub-calendar that does not allow overlap.
event_validation 400 You provided invalid event data when updating or creating an event. See the message key for details.
event_validation_conflict 400 You tried to update or delete an event using an outdated version property because someone else modified it since you last read the event.
invalid_timezone_identifier 400 Invalid timezone identifier provided.
invalid_api_key 400 Invalid API Key provided.

API Usage Best Practices

Scheduled Synchronization

If your API use case requires automatic periodic syncing with Teamup Calendar, it should not sync too frequently and make reasonable use of API calls.

If you do scheduled syncing, you should avoid having it automatically sync at a particular time of the day (for example: on the hour, at midnight, etc).

This might cause our servers to have spikes in traffic at these particular times, which is bad for everyone. It is better to pick a random time offset. For example sync at 13 past instead of 00 on every hour.

Rate Limiting

The API usage is currently unrestricted, but Teamup Calendar reserves the right to impose rate limiting on a per-application basis at a future time if we determine that a poorly designed application is using a disproportionate amount of our resources.