Availability

Custom connector is only available on the Pro tier introduced in March 2022 (not on any legacy Pro tier). To change to the new Pro tier, click here.

Purpose

You can build your own calendar service and integrate it with the Calendar app and make it work just like Google Calendar or Office 365 Calendar. This can be useful for other cloud based calendar services but you can also build a cloud connector for an on-premise calendar solution such as Microsoft Exchange.

Setup

Even when using a calendaring service that isn't visible to the public internet, a proxy can be built which then only needs to be exposed through the firewall but only to the IP addresses of the SweetHawk app server. We strongly recommend using HTTPS exclusively.

Enter your endpoint to your custom calendar service in the Calendar app in the Admin section, note the endpoint must be available on the public internet. You may configure your firewall to only allow SweetHawk's IP addresses documented here.

Authentication

Individual Calendar users can add a custom calendar account by supplying their username and password, which will then be passed on the user's behalf on any API calls.

API definition

An external calendar sync service must provide the following APIs:

List calendars

Must return a list of all calendars for the current user.

GET /calendars

Response
[
{
"Id": "abc1234",
"Name": "My Custom Calendar",
"Color": "LightBlue",
"Owner": null,
"CanEdit": true
},
{
"Id": "def1235",
"Name": "A second one",
"Color": "#cccccc",
"Owner": null,
"CanEdit": false
},
{
"Id": "xyz1236",
"Name": "Cal number 3",
"Color": "LightOrange",
"Owner": {
"Name": "Jane Smith",
"Address": "jsmith@example.com"
},
"CanEdit": true
}
]

Event format

Events must use the following format:

{
"Id": "AAMkAGI2TG93AAA=",
"Subject": "Weekly Meeting on Contoso Project",
"BodyPreview": "Setting up some time to review the budget and planning on the Contoso Project",
"Body": {
"Content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n</head>\r\n<body>\r\nSetting up some time to review the budget and planning on the Contoso Project\r\n</body>\r\n</html>\r\n"
},
"Start": {
"DateTime": "2014-10-13T21:00:00",
"TimeZone": "Pacific Standard Time"
},
"End": {
"DateTime": "2014-10-13T22:00:00",
"TimeZone": "Pacific Standard Time"
},
"Location": {
"DisplayName": "My Office",
"Address": null
},
"IsAllDay": false,
"Attendees": [
{
"EmailAddress": {
"Address": "jschorr@example.com",
"Name": "Janet Schorr"
}
}
],
"Sensitivity": "Private",
"WebLink": "http://example.com/event/event123"
}

Note "WebLink" is a URL that will show the event to the end-user. This does not have to be an internet-facing URL, it can be a private/intranet/local link.

Please use this event format for all APIs below.

List events

List all events in a calendar between specific timeframe between 'start' and 'end' parameters. The 'time_zone' parameter specifies in which time zone the events need to be shown. Recurring events must be expanded into actual occurrences of the event. The purpose of this API is to create a calendar view, so for any recurring events it should only show instances that would fall in the intended time range.

GET /calendars/1/events?start=2020-12-31T23:59:59&end=2021-12-31T23:59:59&time_zone=America/Los_Angeles

Response
[
{
"Id": "event123",
"Subject": "A test event",
"Sensitivity": "Private",
"IsAllDay": true,
"Start": { "DateTime" => "2020-12-31T00:00:00" },
"End": { "DateTime" => "2021-01-01T00:00:00" },
"Location": null,
"WebLink": "http://example.com/event/event123",
},
{
"Id": "event124",
"Subject": "Another test event",
"Sensitivity": "Public",
"IsAllDay": false,
"Start": { "DateTime" => "2020-12-31T22:59:59" },
"End": { "DateTime" => "2020-12-31T23:59:59" },
"Location": { "DisplayName" => "Home" },
"WebLink": "http://example.com/event/event124",
}
]

Show event

Lookup an event by ID.

GET /calendars/1/events/123456

Response
{
"Id": "event124",
...
}

Create event

In writeable calendars, Calendar app will sync events when created on a ticket. This method call is expected to return the ID of the created event in case of success.

POST /calendars/1/events
{
"Subject": "Ticket event",
...
}

Response
{
"Id": 123458
}

Update event

Similar call to create the event, but the update does not need to return anything.

PATCH /calendars/1/events/123456
{
"Subject": "Ticket event",
...
}

Delete event

DELETE /calendars/1/events/123456

Register webhook

Any updates to an event in a calendar can be synced to Calendar app. Calendar app will register a webhook to post any events that are added, changed, or deleted.

POST /calendar/1/subscription
{
"Webhook": "https://zendesk.sweethawk.co/...."
}

Response
{
"Id": 123
}

Your listener subscription should not continue forever but rather have an expiry. Each day when the 2-way sync is still actively listening, we will send further requests to keep the subscription alive. Your service should respond with an identifier of the created subscription, so we can send subsequent calls as:

Keep webhook alive

PATCH /calendar/1/subscription/123
{
"Webhook": "https://zendesk.sweethawk.co/...."
}

To call the webhook, please pass the following payload:

{
"ChangeType": "Created",
"Id": "123459"
}
{
"ChangeType": "Updated",
"Id": "123459"
}
{
"ChangeType": "Deleted",
"Id": "123459"
}

Should the HTTP response be code 410, the sync is no longer needed and the webhook can be removed.

 

 

 

 

 

 


Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.