NAV Navbar
shell php
  • Teamup API Overview
  • Configuration
  • Events
  • Sub-Calendars
  • Access Keys
  • Errors
  • API Usage Best Practices
  • Teamup API Overview

    This API allows programmatic access to calendars hosted by Teamup.

    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');
    
    print $result->getStatusCode();
    // "200"
    
    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": "W",
                "show_day_view": true,
                "show_week_view": true,
                "show_multiday_view": false,
                "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": false,
                "multiweek_number_of_weeks": 8,
                "multiday_number_of_days": 3,
                "agenda_date_range": "3months",
                "agenda_show_details": false,
                "list_date_range": "3months",
                "list_group_by": "month",
                "list_show_details": false,
                "year_number_of_months": 12
            },
            "date_time": {
                "tz_dynamic": false,
                "tz": "Europe/Berlin",
                "tz_show": false,
                "date_locale": "en",
                "use_24h_times": false,
                "time_range_start": 6,
                "time_range_end": 24,
                "start_date_type": "current",
                "start_date": "2016-01-01",
                "start_date_pattern": "y1",
                "week_start": 1,
                "scroll_start_hour": 7
            },
            "identity": {
                "title": "API Demo Calendar",
                "customize": false,
                "show_custom_logo": true,
                "logo_uri": "//teamup.com/app/customlogo/key/ksa87cfc0bcd81ad77",
                "header_background_color": "#D0DEF0",
                "header_font_color": "#444444"
            },
            "link": {
                "name": "Administrator",
                "key": "ksa87cfc0bcd81ad77",
                "id": 1351743
            },
            "features": {
                "calendar_limit": 50,
                "history": 120,
                "daily_agenda": true,
                "passwords": true,
                "file_storage": 10737418240,
                "refresh_param": true,
                "file_upload": true,
                "notification_for_past": true,
                "import_feed_frequency": [
                    43200,
                    10080,
                    720,
                    240,
                    60
                ]
            }
        }
    }
    

    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
    duration int generated (read-only) Event duration in minutes. Only returned if fetching changes.

    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=2017-08-01&endDate=2017-08-31');
    
    print $result->getBody();
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/events?startDate=2017-08-01&endDate=2017-08-01" \
        -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,
            }
        ],
        "timestamp": 1502628855
    }
    

    Retrieve a list of events for a specified date range. This endpoint can be used to periodically synchronize a calendar client with the calendar server.

    HTTP Request

    GET /{calendarKey}/events

    Query Parameters

    Parameter Type Default Description
    startDate date today Optional. The start of the date range to list events from, in YYYY-MM-DD format
    endDate date today +1 day Optional. The end of the date range to list events from (inclusive), in YYYY-MM-DD format
    format string html Optional. 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.
    subcalendarId[] Integer Optional. Use this parameter to restrict the response to selected sub-calendars. This parameter can be applied multiple times to the URL. Eg. &subcalendarId[]=1234&subcalendarId[]=6789.

    Notes

    Get 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 single 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.

    Get Event in iCalendar Format

    Example:

    See shell example
    
    curl "https://teamup.com/ks73ad7816e7a61b3a/events/130178881.ics"
    

    Expected response:

    200 OK
    
    BEGIN:VCALENDAR
    VERSION:2.0
    PRODID:-//Teamup Calendar//Teamup//DE
    CALSCALE:GREGORIAN
    METHOD:PUBLISH
    BEGIN:VEVENT
    SUMMARY:Meeting with Mr. Martens
    X-MICROSOFT-CDO-BUSYSTATUS:BUSY
    LOCATION:Conf. Room 3
    DTSTAMP:20170812T214339Z
    UID:evt130178881@teamup.com
    DTSTART;TZID=UTC:20170810T070000Z
    DTEND;TZID=UTC:20170810T100000Z
    TZID:UTC
    DESCRIPTION:Please prepare coffee and snacks.\n\n\n---\nEvent exported from Teamup, www.teamup.com
    END:VEVENT
    END:VCALENDAR
    

    This endpoint retrieves a specific event and returns it in iCalendar format (content type text/calendar). Important: This request must be addressed at the teamup.com host (not the api.teamup.com host) and does not require an API key. This allows the request to be used with a web browser. Most web browsers are configured to open a calendar application when receiving a response of type text/calendar. This can be used to easily export an event to a third-party calendar program.

    HTTP Request

    GET /{calendarKey}/events/{eventId}.ics

    Create 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 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 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:

    Get Events Changed

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/events?modifiedSince=1501545600');
    
    print $result->getBody();
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/events?modifiedSince=1501545600" \
      -H 'Teamup-Token: API_KEY'    
    

    Expected response:

    200 OK
    
    {
        "events": [
            {
                "id": "130178881",
                "series_id": null,
                "remote_id": null,
                "subcalendar_id": 893615,
                "subcalendar_ids": [
                    893615
                ],
                "start_dt": "2017-08-10T09:00:00+02:00",
                "end_dt": "2017-08-10T12:00:00+02:00",
                "all_day": false,
                "rrule": "",
                "title": "Meeting with Mr. Martens",
                "who": "",
                "location": "Conf. Room 3",
                "notes": "<p>Please prepare coffee and snacks.</p>",
                "version": "598f62832520e",
                "ristart_dt": null,
                "rsstart_dt": null,
                "creation_dt": "2017-08-12T20:18:11+00:00",
                "update_dt": null,
                "delete_dt": null,
                "readonly": true,
                "tz": null,
                "duration": 180
            }
        ],
        "timestamp": 1502628855
    }
    

    Retrieve a list of events that changed recently.

    HTTP Request

    GET /{calendarKey}/events

    Query Parameters

    Parameter Type Default Description
    modifiedSince UNIX timestamp - Required. All events that were created, updated or deleted after this time will be returned.
    format string html Optional. 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.

    Notes

    Search Events

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/events?modifiedSince=1501545600');
    
    print $result->getBody();
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/events?modifiedSince=1501545600" \
      -H 'Teamup-Token: API_KEY'    
    

    Expected response:

    200 OK
    
    {
        "events": [
            {
                "id": "130178881",
                "series_id": null,
                "remote_id": null,
                "subcalendar_id": 893615,
                "subcalendar_ids": [
                    893615
                ],
                "start_dt": "2017-08-10T09:00:00+02:00",
                "end_dt": "2017-08-10T12:00:00+02:00",
                "all_day": false,
                "rrule": "",
                "title": "Meeting with Mr. Martens",
                "who": "",
                "location": "Conf. Room 3",
                "notes": "<p>Please prepare coffee and snacks.</p>",
                "version": "598f62832520e",
                "ristart_dt": null,
                "rsstart_dt": null,
                "creation_dt": "2017-08-12T20:18:11+00:00",
                "update_dt": null,
                "delete_dt": null,
                "readonly": true,
                "tz": null
            }
        ],
        "timestamp": 1502628855
    }
    

    Searches for events using a query string.

    HTTP Request

    GET /{calendarKey}/events

    Query Parameters

    Parameter Type Default Description
    query string - Required. Query string used to search for events. See the Search Guide for supported query syntax and features.
    startDate date today Optional. The start of the date range to search for events, in YYYY-MM-DD format.
    endDate date today +1 day Optional. The end of the date range to search for events, in YYYY-MM-DD format.
    format string html Optional. 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.
    subcalendarId[] Integer Optional. Use this parameter to restrict the response to selected sub-calendars. This parameter can be applied multiple times to the URL. Eg. &subcalendarId[]=1234&subcalendarId[]=6789.

    Notes

    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-Calendar 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 Sub-Calendar

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars/893615');
    
    print $result->getBody();
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars/893615" \
        -H 'Teamup-Token: API_KEY'
    

    Expected response:

    200 OK
    
    {
        "subcalendar": {
            "id": 893615,
            "name": "Frank",
            "active": true,
            "color": 6,
            "overlap": true,
            "type": 0,
            "attributes": [],
            "creation_dt": "2015-06-01T13:51:39+00:00",
            "update_dt": "2017-08-12T20:14:24+00:00",
            "readonly": false
        }
    }
    

    This endpoint retrieves a specific sub-calendar.

    HTTP Request

    GET /{calendarKey}/subcalendars/{subCalendarId}

    Query Parameters

    None

    Create Sub-Calendar

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->post('https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars', [
        'json' => [
            "name" => "Melissa", 
            "active" => true, 
            "color" => 7, 
            "overlap" => true
        ]
    ]);
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars" 
        -XPOST \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json' \
        --data '{
            "name": "Melissa", 
            "active": true, 
            "color": 7, 
            "overlap": true
        }'
    

    Expected response:

    201 Created
    Location: /ks73ad7816e7a61b3a/subcalendars/3619812
    
    {
        "subcalendar": {
            "id": 3619812,
            "name": "Melissa",
            "active": true,
            "color": 7,
            "overlap": true,
            "type": 0,
            "attributes": [],
            "creation_dt": "2017-08-16T09:06:09+00:00",
            "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 Sub-Calendar

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->put('https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars/3619812', [
        'json' => [
            "id" => "3619812",
            "name" => "Melissa Jane", 
            "active" => true, 
            "color" => 9, 
            "overlap" => true
        ]
    ]);
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars/3619812" 
        -XPUT \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json' \
        --data '{
            "id": "3619812",
            "name": "Melissa Jane", 
            "active": true, 
            "color": 9, 
            "overlap": true
        }'
    

    Expected response:

    200 OK
    
    {
        "subcalendar": {
            "id": 3619812,
            "name": "Melissa Jane",
            "active": true,
            "color": 9,
            "overlap": true,
            "type": 0,
            "attributes": [],
            "creation_dt": "2017-08-16T09:06:09+00:00",
            "update_dt": "2017-08-16T09:54:13+00:00",
            "readonly": false
        }
    }
    

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

    HTTP Request

    PUT /{calendarKey}/subcalendars/{subCalendarId}

    Query Parameters

    None

    Delete Sub-Calendar

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->delete('https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars/3619812');
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/subcalendars/3619812" 
        -XDELETE \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json'
    

    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

    Access Keys

    Access keys provide access to the calendar. They are strings of 18 characters and can be used as part of a Web URL to load the calendar into a web browser. For example:

    https://teamup.com/ks73ad7816e7a61b3a

    Each access key has associated permissions that determine which sub-calendars are accessible and what operations can be performed on them.

    Access Key Data Structure

    A access key has the following attributes:

    Parameter Type Default Description
    id int generated (read-only) Access key id
    name string - Access key name, 1 to 50 characters. Name must be unique.
    key string generated Access key string, e.g. ks73ad7816e7a61b3a. This is a generated value that cannot be changed.
    active bool true Whether the access key is active or not
    admin bool false Flag indicating if the key has administrator permission and therefore can manipulate the calendar settings.
    share_type* string all_subcalendars Defines the sharing model used for this access key. See notes below.
    role* string Defines the permission the access key has on sub-calendars. See notes below.
    subcalendar_permissions* array [] An array of pairs of sub-calendar identifier and permission. See notes below.
    require_password bool false Indicates if a password is required when using this access key.
    has_password bool false Indicates if a password has been set for this access key.
    creation_dt date generated (read-only) Creation date
    update_dt date/null generated (read-only) Last update date

    Notes

    Get Access Key Collection

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/keys');
    
    print $result->getBody();
    
    curl "http://api.teamup.com/ks73ad7816e7a61b3a/keys" \
        -H 'Teamup-Token: API_KEY'
    

    Expected response:

    200 OK
    
    {
        "keys": [
            {
                "id": 1351743,
                "name": "Administrator",
                "key": "ksa8fc0bedfd81ad77",
                "active": true,
                "admin": true,
                "share_type": "all_subcalendars",
                "role": "admin",
                "subcalendar_permissions": [],
                "require_password": false,
                "has_password": false,
                "email": null,
                "user_id": null,
                "creation_dt": "2015-06-01T13:51:39+00:00",
                "update_dt": null
            }, {
                "id": 1351768,
                "name": "Authenticated",
                "key": "kscb1caezduce9f0a8",
                "active": true,
                "admin": false,
                "share_type": "all_subcalendars",
                "role": "modify_from_same_link",
                "subcalendar_permissions": [],
                "require_password": true,
                "has_password": true,
                "email": null,
                "user_id": null,
                "creation_dt": "2015-06-01T13:58:13+00:00",
                "update_dt": "2015-06-01T13:58:40+00:00"
            },{
                "id": 4739545,
                "name": "Linda",
                "key": "ksa2wavezv53er56dg",
                "active": true,
                "admin": false,
                "share_type": "selected_subcalendars",
                "role": "mixed",
                "subcalendar_permissions": {
                    "893615": "no_access",
                    "893616": "modify",
                    "3606264": "read_only",
                    "3606266": "add_only",
                    "3607516": "no_access",
                    "3620740": "read_only"
                },
                "require_password": false,
                "has_password": false,
                "email": null,
                "user_id": null,
                "creation_dt": "2017-08-27T17:41:40+00:00",
                "update_dt": "2017-09-03T12:07:54+00:00"
            }
        ]
    }
    

    This endpoint returns a list of all access keys for the calendar.

    HTTP Request

    GET /{calendarKey}/keys

    Query Parameters

    None

    Get Access Key

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->get('https://api.teamup.com/ks73ad7816e7a61b3a/key/4788218');
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/key/4788218" 
        -H 'Teamup-Token: API_KEY'
    

    Expected response:

    200 OK
    
    {
        "key": {
            "id": 47788218,
            "name": "Michelle",
            "key": "ksxok7didijdgywijb",
            "active": true,
            "admin": false,
            "share_type": "all_subcalendars",
            "role": "read_only",
            "subcalendar_permissions": [],
            "require_password": false,
            "has_password": false,
            "creation_dt": "2017-09-04T06:42:38+00:00",
            "update_dt": null
        }
    }
    

    This API endpoint can be used to retrieve an access key.

    HTTP Request

    GET /{calendarKey}/keys/{keyId}

    Query Parameters

    None

    Create Access Key

    Example 1: Create a new access key with the same permission for all sub-calendars.

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->post('https://api.teamup.com/ks73ad7816e7a61b3a/keys', [
        'json' => [
            "name" => "Michelle", 
            "active" => true, 
            "admin" => false,
            "require_password" => false,
            "password" => "",   
            "share_type" => "all_subcalendars",
            "role" => "read_only"
        ]
    ]);
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/keys" 
        -XPOST \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json' \
        --data '{
            "name": "Michelle", 
            "active": true, 
            "admin": false,
            "require_password": false,
            "password": "", 
            "share_type":"all_subcalendars",
            "role":"read_only"
        }'    
    

    Expected response:

    201 Created
    Location: /ksxok7didijdgywijb/keys/47788218
    
    {
        "key": {
            "id": 47788218,
            "name": "Michelle",
            "key": "ksxok7didijdgywijb",
            "active": true,
            "admin": false,
            "share_type": "all_subcalendars",
            "role": "read_only",
            "subcalendar_permissions": [],
            "require_password": false,
            "has_password": false,
            "creation_dt": "2017-09-04T06:42:38+00:00",
            "update_dt": null
        }
    }
    

    Example 2: Create a new access key with different permissions for different sub-calendars.

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->post('https://api.teamup.com/ks73ad7816e7a61b3a/keys', [
        'json' => [
            "name" => "Michelle", 
            "active" => true, 
            "admin" => false,
            "require_password" => false,
            "password" => "",   
            "share_type" => "selected_subcalendars",
            "subcalendar_permissions": [
                "893615" => "no_access",
                "893616" => "read_only",
                "3606264" => "add_only",
                "3606266" => "read_only_without_details",
                "3607516" => "modify",
                "3620740" => "modify_from_same_link"
            ]
        ]
    ]);
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/keys" 
        -XPOST \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json' \
        --data '{
            "name": "Michelle", 
            "active": true, 
            "admin": false,
            "require_password": false,
            "password": "", 
            "share_type":"selected_subcalendars",
            "subcalendar_permissions": {
                "893615": "no_access",
                "893616": "read_only",
                "3606264": "add_only",
                "3606266": "read_only_without_details",
                "3607516": "modify",
                "3620740": "modify_from_same_link"
            }
        }'    
    

    Expected response:

    201 Created
    Location: /ks93k3juz54rd6faf6/keys/4778606
    
    {
        "key": {
            "id": 4778606,
            "name": "Michelle",
            "key": "ks93k3juz54rd6faf6",
            "active": true,
            "admin": false,
            "share_type": "selected_subcalendars",
            "role": "mixed",
            "subcalendar_permissions": {
                "893615": "no_access",
                "893616": "modify",
                "3606264": "add_only",
                "3606266": "no_access",
                "3607516": "read_only",
                "3620740": "no_access"
            },
            "require_password": false,
            "has_password": false,
            "creation_dt": "2017-09-04T05:42:18+00:00",
            "update_dt": null
        }
    }
    

    This API endpoint can be used to create a new access key.

    HTTP Request

    POST /{calendarKey}/keys

    Query Parameters

    None

    Update Access Key

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->put('https://api.teamup.com/ks73ad7816e7a61b3a/keys/4709149', [
        'json' => [
            "id" => 4709149,
            "name" => "Michelle",
            "active" => true,
            "admin" => false,
            "require_password" => false,
            "password" => "",
            "share_type" => "all_subcalendars",
            "role" => "read_only"
        ]
    ]);
    
    curl "https://api.teamup.com/ks73a35htdd7a61b3a/keys/4709149" 
        -XPUT \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json' \
        --data '{
            "id": 4709149,
            "name": "Michelle",
            "active": true,
            "admin": false,
            "require_password": false,
            "password": "",
            "share_type": "all_subcalendars",
            "role": "read_only"
        }'    
    

    Expected response:

    200 OK
    
    {
        "key": {
            "id": 4709149,
            "name": "Michelle",
            "key": "ks3zf99udzd6dzd6vd",
            "active": true,
            "admin": false,
            "share_type": "all_subcalendars",
            "role": "read_only",
            "subcalendar_permissions": [],
            "require_password": false,
            "has_password": false,
            "creation_dt": "2017-08-21T20:52:03+00:00",
            "update_dt": "2017-09-04T13:14:39+00:00"
        }
    }
    
    

    This API endpoint can be used to update an existing access key.

    HTTP Request

    PUT /{calendarKey}/keys/{keyId}

    Query Parameters

    None

    Delete Access Key

    Example:

    <?php
    
    $client = new GuzzleHttp\Client(['headers' => ['Teamup-Token' => 'API_KEY']]);
    $result = $client->delete('https://api.teamup.com/ks73ad7816e7a61b3a/keys/47463537');
    
    curl "https://api.teamup.com/ks73ad7816e7a61b3a/keys/47463537" 
        -XDELETE \
        -H 'Teamup-Token: API_KEY' \
        -H 'Content-type:application/json'
    

    Expected response:

    204 No Content
    

    This endpoint can be used to delete an access key.

    HTTP Request

    DELETE /{calendarKey}/keys/{keyId}

    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.