An introduction to the API for OnTime for IBM

91
ONTIME | Group Calendar AN INTRODUCTION TO THE ONTIME API

Transcript of An introduction to the API for OnTime for IBM

ONTIME | Group Calendar

AN INTRODUCTION TO THE ONTIME API

Agenda (part 1)• Introduction• Demos – seeing is believing• Core Concepts• API Explorer• OnTime Frameworks• How we did the demos – code walk-thru

Agenda (part 2)• Advanced Topics (character encoding, logging,

batching commands, etc.)• Access Examples (JavaScript, Java, LotusScript)• Native IBM Notes (NRPC) Access• Reference Material

INTRODUCTION

Target Audience• OnTime Group Calendar– Customers– Partners

• Developers• Solution Architects

Many User Interfaces1. Notes2. Browser3. Mobile4. Sidebar5. Social6. Room Signs

1 API• This is an API created and

maintained by OnTime – not by IBM

• Everything we do in the user interfaces you can do with the API as well – there are no secret calls

• New user interface features adds new capabilities to the API e.g. when we added Out of Office functionality it became available to API customers

Requirements• OnTime Group Calendar installed and configured• Open API License – purchased separately – price

based on total license price• Application ID – issued by OnTime on request– All installations come with a special Application ID called

”ApiExplorer” – don’t use for production as it’s throttled• Access by a user in OnTime

Skills Required• JSON (JavaScript Object Notation)• IBM Notes/Domino API for LotusScript / Java

access via NRPC• Virtually any other programming language for

access via HTTP(S)

What can you do with it?• Custom user interfaces• Custom reports and analysis• Integration– CRM systems– Phone systems– Booking systems

DEMOSSEEING IS BELIEVING…

Demos• JavaScript and Java– Create appointment– Read calendar entries– Free time search– Out of Office

• XPages– Use Java framework to build application

CORE CONCEPTS

Endpoints• An endpoint is the ”address” you make API

requests against• OnTime supports two types of endpoints– HTTP using URL’s– NRPC using an agent

• This presentation will focus on using HTTP (there are slides on NRPC near the end)

HTTP Endpoint in Detail• HTTP uses two endpoints – one for getting an Access Token and

one for data• An Access Token is required for all API data access• The API endpoints are in the Client database

1. Token – /ontime/ontimegcclient.nsf/apihttptoken2. Data – /ontime/ontimegcclient.nsf/apihttp

• If using the servlet (offers caching and much higher performance) for API access 1. Data (servlet) – /servlet/ontimegc

Access Token (”token”)• All requests to the token endpoint requires you to be authenticated to

IBM Domino (basic, form, certificate)• All requests to the API endpoint requires a token obtained from the Token

endpoint• A token may be used without the user being authenticated to IBM Domino• A token may be cached – expiration set in configuration (Server

Settings/OnTime Token Timeout)• From API version 5 the token is fully cluster and load balancer compliantPlease note: New token returned with each request – doesn’t expire the old one though – ”timeout” is in effect an Idle Timeout

JSON (1)• Industry standard – http://www.json.org• Some languages like JavaScript has native support for

JSON• Some languages like Java and LotusScript require a

separate parser to consumer and writer to produce JSONBonus: We supply a JSON parser and writer for LotusScript that you may use with the OnTime API

JSON (2){

”name”: ”Chris Holmes”, ”age”: 34,”male”: true,”emails”: [”[email protected]”, ”[email protected]”],”address”: {”street”: ”101 Main Street”,”zipcode”: ”23821”,”city”: ”Cleveland””country”: ”USA”}

} Please note: Keys are in quotes

JSON (3){

”product”: ”OnTime\u00ae Group Calendar”, ”userInterfaces”: [{”name”: ”Notes”, ”language”: ”Java”},{”name”: ”Browser”, ”langauge”: ”JavaScript”},{”name”: ”Mobile”, ”language”: ”JavaScript”},{”name”: ”Social”, ”language”: ”JavaScript”},{”name”: ”Sidebar”, ”language”: ”Java”}]

}

Please note: Keys are case sensitive

Please note: Non-ASCII characters shouldbe Unicode encoded – very important whenusing the agent based API (HTTP only)

Operations• An operation is a ”command” you send the API to let it know what you

would like to do• Currently 40+ different operations• Examples

– Login (current user information)– Version (retrieve version information)– UsersAll (retrieve users)– Calendar (retrieve calendar entries)– AppointmentCreate (create a calendar entry)– OutOfOfficeGet (retrieve out of office information)

Application ID and Version• All requests must contain an Application ID

(ApplID) in the Main section– The Application ID is verified against your OnTime

Group Calendar license key• All requests must contain an Application Version

(ApplVer) in the Main section– The Application Version may be any string

API Versioning• To be backwards compatible the API is versioned– From v. 4.4 we will be at APIVer=6

• API versioning allows us to continueously update the API and add new features without breaking custom applications

• API version is specified using ”APIVer” key in the Main section

• You must specify an API version for each request

Basic Request Format• Each request must contain a payload describing the request• The payload always has a Main section with APIVer, ApplID, ApplVer and a Token{

”Main”: {”APIVer”: 6, ”ApplID”: ”ApiExplorer”,”ApplVer”: ”0.0.1”,”Token”: ”<access token>”},”Command1”: {<command specific data>}

}

Basic Response Format• The response always contains an overall status

code, the server API version, a new token and a response object per command sent

{”APIVersion”: ”4.2.0”, ”Command1”: {...},”Token”: ”1234567890abcdefghijk==”,”Status”: ”OK”

}

Example – obtaining a tokenPOST >> apihttptokenAuthorization: Basic ZGVtbzpkZW1v

{”Main”: {”APIVer”: 6, ”ApplID”: ”ApiExplorer”,”ApplVer”: ”0.0.1”

}}

{”APIVersion”: ”4.2.0”,”APIBuild”: 650,”Token”: ”abc111==”,”Status”: ”OK”

}

Example –the Login operationPOST >> apihttp

{”Main”: {”APIVer”: 6, ”ApplID”:

”ApiExplorer”,”ApplVer”: ”0.0.1”,”Token”, ”abc111==”

}, ”Login”: {}}

{”APIVersion”: ”4.2.0”,”Login”: { ”Global”: {...}, ”User”: {”ID”: ”X”, ”Name”: ”Chris Holmes/OnTime”, ”Email”: ”[email protected]”, ”MailSource”: ”Domino” }},”Token”: ”abc222==”,”Status”: ”OK”}

Handling Errors• If an error occurs it is sent back to the caller• The error contains an error code and a description• It is a best practice to always verify that ”Status” is ”OK”

{APIVersion: "4.2.0”,Status: "Error”,ErrorCode: "NotValidApplID”,Error: "Not a valid Application

ID"}

{APIVersion: "4.2.0”,Status: "Error”,ErrorCode: "TokenTimeout”,Error: "Token Timeout"

}

Dates• All dates should be encoded as strings in ISO8601 format

using the UTC timezone– {YYYY}-{MM}-{dd}T{HH}:{mm}:{ss}Z

• UTC doesn’t adjust for daylight savings time• OnTime provided frameworks handle time zone conversion

automatically• Please note: Using UTC may be confusing at first as a the

date/time may be ”tomorrow” or ”yesterday”

Dates• 2015-12-31T13:15:00Z

– 2.15pm, 31 December 2015 in Denmark (UTC+1, winter time)– 10.15pm, 31 December 2015 in Japan (UTC+9)

• 2015-06-23T22:00:00Z– Midnight, 24 June 2015 in Denmark (UTC+2, summer time)– 7am, 24 June 2015 in Japan (UTC+9)

• 2015-06-30T15:00:00Z– 8am, 30 June 2015 in California, (UTC-7)– Midnight, 1 July 2015 in Japan (UTC+9)

API EXPLORER

Getting the API Explorer• You already have it – it is in the Clients database

– http://<hostname>/<ontime client db>/apiexplorer– https://demo.ontimesuite.com/ontime/ontimegcclient.nsf/apiexplorer (same as https://demo.ontimesuite.com/apiexplorer)

• It’s the tool we use when we develop for OnTime• Preconfigured with ApiExplorer Application ID for

testing

Demo – API Explorer

• Show API Explorer• Log in, obtain token and do requests• Show how the API Explorer lets you

inspect requests and responses• Log out and continue to do requests• Show built in examples

ONTIME FRAMEWORKS

Current Stack

OnTime Core Server

OnTime API(”low level” JSON based API)

Notes

JavaJavaScript

Team-At-A-GlanceMobileWeb

CustomApp

Room

Sig

ns Social

Soci

al

Coming Stack

OnTime Core Server

OnTime API(”low level” JSON based API)

Cust

om A

pp

Java FrameworkJavaScript Framework (ivcore.js)

Team-At-A-Glance

Mobile(new)WebCustom

AppCustom

AppRoom Signs Notes SocialSocial

Mob

ile (i

OS)

The Goal• Do not reinvent the wheel – calendaring and timezones

are hard to get right so use our code• Time proven code – the framework code is what’s in the

products – it’s not something we make just for customers

• The frameworks handle authentication, tokens, network transport and often dealing with the underlying data

HOW WE DID THE DEMOS

JavaScript Examples• Create appointment• Read calendar entries• Free time search• Out of Office

Create Appointment, JavaScript// create appointmentivcore.api.AppointmentCreate({

"UserID": this.userID,"Subject": this.getFormFieldValue("subject"),"Location": this.getFormFieldValue("location"), "StartDT": this.getFormFieldValue("start"), "EndDT": this.getFormFieldValue("end")

});ivcore.api.process(function(json) {

if (json.Status === ”OK”) {...

}}.bind(this));

Read Calendar Entries, JavaScript// read calendar entriesivcore.api.Calendars({

"FromDT": start,"ToDT": end,"IDs": [this.userID]

});ivcore.api.process(function(json) {

// get calendar entries and sort using wrapper classvar calitems = new

iv.ontimegc.CalItemArr(json.Calendars.IDs[0].Items);calitems.sort();...

}.bind(this));

Free Time Search, JavaScript// perform freetime searchivcore.api.FreeTimeSearch({

"FromDT": from,"ToDT": to,"IDs": this.searchIDs,"Duration": 360

});ivcore.api.process(function(json) {

...}.bind(this));

Out Of Office, JavaScript// request OOO for a userivcore.api.OutOfOfficeGet({

"UserID": this.userID});ivcore.api.process(function(json) { if (json.Status === ”OK”) { // read OOO info and use wrapper class for date/time formatting var ooo = json.OutOfOfficeGet; var dateBack = ooo.DateTimeBack.ivToDate(); var strBack = ivcore.langreg.region("<dd MMM, HH:NN>", dateBack); ... }}.bind(this));

Java Examples• Create appointment• Read calendar entries• Free time search• Out of Office

Create Appointment, Java (1)// create facade with default values (and configure, omitted for brevity)IGroupCalendarAPIFacade facade = new GroupCalendarAPIFacade();

// create appointmentCalEntryResponse response = facade.createAppointment(null,

120, "Test Appointment",

"OnTime Example Code");if (response.isSuccess()) {

System.out.println("Created appointment”);}

Create Appointment, Java (2)// create facade with default values (and configure, omitted for brevity)IGroupCalendarAPIFacade facade = new GroupCalendarAPIFacade();

// create calendar and get dates using utility classes Calendar cal = facade.createJavaCalendar();CalendarUtil.setTime(cal, 13, 0);Date start = cal.getTime();CalendarUtil.setTime(cal, 14, 0);Date end = cal.getTime();

// create appointmentCalEntryResponse response = facade.createAppointment(start, end, "Test Appointment",

"OnTime Example Code");if (response.isSuccess()) {

System.out.println("Created appointment”);}

Read Calendar Entries, Java// create facade with default values (and configure, omitted for brevity)IGroupCalendarAPIFacade facade = new GroupCalendarAPIFacade();

// create date/time range (date construction omitted for brevity)DateTimeRange range = new DateTimeRange(start, end);

// fetch appointmentsfacade.fetchAppointments(false, range);

// get appointmentsIAppointment[] apps = facade.getActAsCalendar().getAppointments();

// show resultfor (IAppointment app : apps) { System.out.println(app.getDateTimeRange() + " - " + app.getSubject());}

Free Time Search, Java// create facade with default values (and configure, omitted for brevity)IGroupCalendarAPIFacade facade = new GroupCalendarAPIFacade();

// create dates (date construction omitted for brevity)Date from = ...Date to = ...

// get calendarsDate[] results = facade.searchFreeTime(60, from, to,

ID_TYPE.EMAIL, "[email protected]", "[email protected]");

for (int i=0, count=ArrayUtil.count(results); i<count; ) {Date d1 = results[i++];Date d2 = results[i++];System.out.println(d1 + " --> " + d2);

}

Out of Office, Java// create facade with default values (and configure, omitted for brevity)IGroupCalendarAPIFacade facade = new GroupCalendarAPIFacade();

// actually fetch OOOOutOfOfficeResult ooo = facade.fetchOutOfOffice();

// show resultSystem.out.println("Out of office for <" +

facade.getActAsUser().getDispName() + ”> of is <" + (ooo.isEnabled() ? "ENABLED" : "DISABLED") + ">");

System.out.println(ooo.getDateOut());System.out.println(ooo.getGeneralSubject());System.out.println(ooo.getGeneralBody());

XPages Example• Let us do a code walk-thru in Domino Designer• Techniques used– Jar design elements w/ OnTime Java Framework– Data tables to loop data– AppointmentFilter for easy filtering and sorting

ADVANCED TOPICS

Character Encoding• It is a best practice to always encode non-ASCII charcters

using the Unicode character code using \uXXXX– ® == \u00ae– 東 == \u6771– 京 == \u4EAC

• Failure to do so may result in character encoding issues• OnTime provided frameworks handle character encoding

automatically

Character Encoding{"Main" : {   "APIVer": 5,   "ApplID": "ApiExplorer",   "ApplVer": "0.0.1" }, "AppointmentCreate": {   "AppointmentType": "0",   "UserID": "7",   "StartDT": "2015-05-18T07:00:00Z",   "EndDT": "2015-05-18T10:00:00Z",   "Subject": "OnTime API ワークショップ ",   "Location": "新宿区 , 東京 " }

Character Encoding{"Main" : {   "APIVer": 5,   "ApplID": "ApiExplorer",   "ApplVer": "0.0.1" }, "AppointmentCreate": {   "AppointmentType": "0",   "UserID": "7",   "StartDT": "2015-05-18T07:00:00Z",   "EndDT": "2015-05-18T10:00:00Z",   "Subject": "OnTime API \u30EF\u30FC\u30AF\u30B7\u30E7\u30C3\u30D7",   "Location": "\u65B0\u5BBF\u533A, \u6771\u4EAC" }

More on Tokens• As mentioned previously a token may be cached on the client• When caching please be aware of token expiration – expiration time is set on the server –

defaults to 24 hours• A token may be revoked on the server by forcing a new web logon (see screeenshot, means

setting a new ”token ID” for the user)• Token related error codes

– NoToken– NoUserWithToken– TokenTimeout– WrongTokenID– InvalidTokenTimeType– TokenDecryptError– WrongTokenSign

API Log (1)

The API log is an excellent debugging tool as it shows exactly what the API received and what it returned

API Log (2)• Starting with v. 4.0 – API logging is no longer only

controllable on the OnTime server document but from code and on a per user basis

• There are 3 ways to have API traffic logged for a user

• Please note: Never leave API logging turned on in production as it may affect performance.

API Log (3)1. The Main section contains ”APILog” = true

Controlled by application code and enabled logging only for the specific calls

{"Main": {"APIVer": 6, "ApplVer": "0.0.1", "ApplID": "ApiExplorer", "Token": ”aaa111==", "APILog": true}, "Login": {}}

API Log (4)2. Enable user debug – enables logging for all calls

until turned of. Benefit is that it’s done on the server (no app changes). Setting actually does two things:– Enables extended logging

for the user (sync. logging)– Enables API logging

API Log (5)3. OnTime UI specific option (actually toggles on APILog=true)

– Web UI by appending &debug=true– Eclipse UI’s through menu actions

OnBehalfOf• All operations are performed as the current user (as

represented by the token / signer)• For some applications you may need to act as someone else –

we call this OnBehalfOf• Access to use OnBehalfOf

is explicitly granted on a per user basis in Server Settings (set on all servers)

OnBehalfOf – Login as user selfRequest{"Main": {"APIVer": 6, "ApplVer": "0.0.1", "ApplID": ”ApiExplorer", "Token": "aaa111=="}, "Login": {}}

(Logged in as Chris Holmes/OnTime)

Response{"APIVersion":"4.1.4","APIBuild":655,"Login":{"Global":{"PreSort":false,"SyncBack":21,"PhotoEnabled":true},"User":{"ID":"7","Name":”Chris Holmes/OnTime","Email":”[email protected]","MailSource":"Domino"},"SectionProcessTime":16},"Token":”aaa222==","Status":"OK"}

OnBehalfOf – Login w/ OnBehalfOfRequest{"Main": {"APIVer": 6, "ApplVer": "0.0.1", "ApplID": ”ApiExplorer", "Token": "aaa222==", ”OnBehalfOf": ”Amanda Jones/OnTime"}, "Login": {}}

(Logged in as Chris Holmes/OnTime and he’s allowed to do OnBehalfOf requests)

Response{"APIVersion":"4.1.4","APIBuild":655,"Login":{"Global":{"PreSort":false,"SyncBack":21,"PhotoEnabled":true},"User":{"ID":"1","Name":”Amanda Jones/OnTime","Email":”[email protected]","MailSource":"Domino"},"SectionProcessTime":0},"Token":”aaa333==","Status":"OK"}

OnBehalfOf – GetToken (1)Request{"Main": {"APIVer": 5, "ApplVer": "0.0.1", "ApplID": ”ApiExplorer", "Token": "aaa333==", ”OnBehalfOf": ”Amanda Jones/OnTime"}, ”GetToken": {}}

Response{"APIVersion":"4.1.4","APIBuild":655,"GetToken":{"Token":”bbb111==","User":”Amanda Jones/OnTime","ID":"1","CurrentTimeout":168,"SectionProcessTime":0},"Token":”aaa444==","Status":"OK"}

Excellent solution for performing Single-Sign-On with portals built on other technologies than IBM – issue a token to the user and save in a cookie…

OnBehalfOf – GetToken (2)Request{"Main": {"APIVer": 5, "ApplVer": "0.0.1", "ApplID": ”ApiExplorer", "Token": ”bbb111==”}, ”Login": {}}

Response{"APIVersion":"4.1.4","APIBuild":655,"Login":{"Global":{"PreSort":false,"SyncBack":21,"PhotoEnabled":true},"User":{"ID":"1","Name":”Amanda Jones/OnTime","Email":”[email protected]","MailSource":"Domino"},"SectionProcessTime":0},"Token":”bbb222==","Status":"OK"}Now just using token

obtained on previous slide

Batching commands (1)• Each request to the API may contain multiple commands –

even multiple versions of the same command (e.g. multiple OutOfOfficeGet)

• We call this ”batching commands”• Keys must be unique in JSON so the API only checks the

beginning of the keys– OutOfOfficeGet == OutOfOfficeGet_MySuffix

• Response uses the same keys as the request

Batching commands (2)Request{"Main": {

"APIVer": 5, "ApplVer": "0.0.1", "ApplID": "ApiExplorer", "Token": ”aaa111=="}, "Login_1": {}, "Login_XYZ": {}

}

Response{"APIVersion":"4.1.4","APIBuild":655,"Login_1":{"Global":{…},"User":{"ID":"7","Name":”Chris Holmes/OnTime","Email":”[email protected]","MailSource":"Domino"},"SectionProcessTime":0},"Login_XYZ":{"Global":{…},"User":{"ID":"7","Name":”Chris Holmes/OnTime","Email":”[email protected],"MailSource":"Domino"},"SectionProcessTime":0},"Token":”aaa222==","Status":"OK"}

Custom ID (1)• When doing multiple requests – even multiple requests

at the same time – keeping track of them can be hard• To make it easier to discern the requests you may add a

custom ID to each request• The custom ID is returned in the corresponding

response• The custom ID may be any string value

Custom ID (2)Request{"Main": {

"APIVer": 5, "ApplVer": "0.0.1", "ApplID": "ApiExplorer", "Token": ”aaa111==",”CustomID":

”MyCustomID”}, "Login": {}

}

Response{"APIVersion":"4.1.4","APIBuild":655, "CustomID": "MyCustomID", "Login":{"Global":{…},"User":{"ID":"7","Name":”Chris Holmes/OnTime","Email":”[email protected]","MailSource":"Domino"},"SectionProcessTime":0},"Token":”aaa222==","Status":"OK"}

USING PLAIN JAVASCRIPT

Character Encoding

Access w/ JavaScript (1)var apirequest = function(payload, callback) { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST", ”/servlet/ontimegc", true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { if (xmlhttp.status == 200) { // handle response var result = JSON.parse(xmlhttp.responseText); if (callback) callback(result); } } } // post xmlhttp.send(JSON.stringify(payload));}

Access w/ JavaScript (2)// payloadvar payload = {"Main": {"APIVer": 6, "ApplID": "ApiExplorer", "ApplVer": "0.0.1", "Token": "aaa111=="}, "Login": {}};

// do requestapirequest(payload, function(obj) { console.log(obj);});

USING PLAIN JAVA

Character Encoding

Access w/ Java (1) URL url = new URL(https://demo.ontimesuite.com/servlet/ontimegc"); HttpURLConnection con =(HttpURLConnection)url.openConnection(); con.setRequestMethod("POST"); con.addRequestProperty("Content-Type", "application/json"); con.addRequestProperty("Accept", "*/*"); con.setDoInput(true); // handle post con.setDoOutput(true); OutputStream out = con.getOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out)); writer.write(request); writer.flush();

Access w/ Java (2) // get response code and read response if code 200 (OK) if (200 != con.getResponseCode()) throw new Exception("Non OK"); BufferedReader reader = new BufferedReader(

new InputStreamReader(con.getInputStream())); StringBuilder buffer = new StringBuilder(2048); String line = null; while (null != (line = reader.readLine())) { buffer.append(line).append('\n'); } // disconnect and return result; con.disconnect(); return buffer.toString();

USING NRPCNative IBM Notes API Access via Notes Remote

Procedure Calls

Endpoints in Detail (NRPC)• Starting with version 3.8 all API requests are made

against a single database – the Client database1

• API requests are done by 1. Creating/updating a document in the Client database2. Signing the document (NotesDocument.sign())3. Running an agent on the server with the document as context

• The agent is called ApiNotes and can be found in the Client database

1 Prior to this version there were two possible API endpoint databases; 1) the API database and 2) the Web database

Authentication• User access is verified using IBM Notes digital signatures• Ideal for LotusScript as HTTP access is troublesome• May be used with Java as well• Requires access to the IBM Notes/Domino backend API (Local

or DIIOP)• Cluster and failover aware through the IBM Notes/Domino

API• Please note: NRPC access doesn’t use OnTime Access Tokens

Access w/ NRPC (1)Requests are done as follows:

1. Create/update an API document in the Client database2. Set JSON request (same payload as with HTTP)3. Set Authors field (ensure only user and server can read document)4. Sign document5. Run (ApiNotes) agent on document on the server6. Refetch the API document7. Read the JSON response

Access w/ NRPC (2)Requests are done as follows:

1. Create/update an API document in the Client database2. Set JSON request in a field called $Request_0 (if bigger than 32 kb continue in

$Request_1 and so on…)3. Set Authors field called _Authors to

[ReadAll], <Server DN>, <User DN>4. Sign document (NotesDocument.Sign())5. Run (ApiNotes) agent on document on the server (NotesAgent.RunOnServer(noteid))6. Refetch the API document by note ID7. Read the JSON response from a field called $Response_0 (if bigger than 32 kb

continue in $Response_1 and so on)

Access w/ LotusScript (1)Function ProcessString(Request As String) As String

Dim session As New NotesSessionDim dbApi As NotesDatabaseDim agentApi As NotesAgentDim docApi As NotesDocumentDim noteid As StringDim item As NotesItemDim values(0 To 2) As String

values(0) = session.UserNamevalues(1) = "[ReadAll]"values(2) = session.EffectiveUsername

Set dbApi = session.GetDatabase("Server1/OnTime", "ontime/ontimegcclient.nsf")Set agentApi = dbApi.GetAgent("ApiNotes")Set docApi = New NotesDocument(dbApi)Call SetLongString(docApi, "$Request", Request)Set item = New NotesItem(docApi, "_Author", values)item.Isauthors = trueitem.Isreaders = trueCall docApi.Sign()Call docApi.Save(True,False)noteid = doc.Noteid

Delete docApiCall agentApi.Runonserver(noteid)Set docApi = dbApi.GetDocumentByNoteID(noteid)

ProcessString = GetLongString(docApi, "$Response")Exit Function

Declarations

Access for API document

Access Client database,API agent, create API document,

sign and save

Delete document reference, run agent on and refetch document

Read response

Character Encoding in LotusScriptPrivate Function encode(s As String) As String Dim result As String Dim i As Integer Dim ch As String Dim u As Long For i = 1 To Len(s) ch = Mid(s,i,1) u = Uni(ch) Select Case u Case 34 : result = result & {\"} Case 92 : result = result & {\\} Case 47 : result = result & {\/} Case 8 : result = result & {\b} Case 12 : result = result & {\f} Case 10 : result = result & {\n} Case 13 : result = result & {\r} Case 9 : result = result & {\t} Case Else If (u>=32) And (u<127) Then result = result & ch Else result = result & "\u" & Right("0000" & Hex(u), 4) End If End Select Next encode = resultEnd Function

If (u>=32) And (u<127) Then r = r & chElse u = Uni(ch) r = r & "\u" & Right("0000" & Hex(u), 4)End If

LotusScript Examples1. Login (Does a login request to the server)2. Version (requests the version information from the

server)3. Calendars, raw (requests 7 days worth of calendar

information for the current user by DN)4. Calendars, processed (same as 3 but parses the

response using the JSON parser)

REFERENCE MATERIAL

Operations• Login• Logout• Version• UsersAll• UsersInfo• Calendars• AppointmentCreate• AppointmentChange• AppointmentRemove• AppointmentRead• AppointmentInviteeStatus• AppointmentRepeatDates• CustomFieldsList• FreeResources

• FreeRooms• FreeTimeSearch• GetToken• GroupList• GroupPrivateChange• GroupPrivateRemove• GroupUserIDs• LanguageList• LanguageText• Legends• LegendsSets• LegendsSetsList• MailSend• NameFormat• NoticeAccept

• NoticeDecline• NoticeUpdate• Notices• OutOfOfficeGet• OutOfOfficeSet• RegionList• RegionText• SettingsGet• SettingsSet• UserBusyInfo• UsersAccess• UsersPhoto• UsersSearch

Links• OnTime Group Calendar demo environment https://demo.ontimesuite.com

• OnTime Group Calendar demo API Explorerhttps://demo.ontimesuite.com/apiexplorer(login with username ”demo” and password ”demo”)

Main object keysKey name Description Required

ApplID Application ID – issued by OnTime support on request.

ApplVer Application version – can be any string

APIVer API version to use. Currently it should be 5. From v. 4.4 it should be 6.

Token The token to identify the user if using HTTP

CustomID Custom string to discern multiple concurrent requests

APILog Should the API request be logged on the server

OnTime Group Calendar databases• Configuration database

– Default location: /ontime/ontimegc.nsf• Log database

– Default location: /ontime/ontimegclog.nsf• Client database

– Default location: /ontime/ontimegcclient.nsf• Broadcast database

– Default location: /ontime/ontimegcbroadcast.nsf