This guide provides a general overview of the REST v2 API
Please see here for comprehensive documentation
The v2 REST API offers programmatic access to common ClickTime functions. It is not an iteration on our existing APIs, but rather a redesign intended to follow RESTful principles. As a result, we now have a REST API that:
- Makes exclusive use of JSON for request and response bodies
- Uses semantic HTTP status codes
- Supports filtering and pagination of results
- Supports batch requests and responses
Our v2 REST API was selected as one of the top APIs in the Business software category by API World in 2019!
Most API endpoints only support authentication via token. The only exceptions to this rule are as follows:
- The GET /Me endpoint additionally supports basic access authentication so you can retrieve your API token.
- The POST /Me/ResetAuthToken endpoint only supports basic access authentication.
Clients can authenticate themselves with their username and password using basic HTTP authentication against the “Me” endpoint in order to obtain a token.
Examples of Basic Authentication:
Make a request like the one below but replacing "EMAIL" with your email address as it's listed in ClickTime and "PASSWORD" with your ClickTime password.
curl -X GET \
https://api.clicktime.com/v2/me \
--user EMAIL:PASSWORD
Alternatively, you can also do the following to avoid entering your email and password in clear text:
- Build a string in the form of EMAIL:PASSWORD in which "EMAIL" is your email address as it's listed in ClickTime and "PASSWORD" is your ClickTime password.
- Base64 encode the above string
- Make a request like the one below but replacing "ENCODED_STRING" with the encoded string you created in the previous step.
curl -X GET \
https://api.clicktime.com/v2/me \
-H 'Authorization: Basic ENCODED_STRING' \
Clients can use a custom per-user authentication token by sending an Authorization header in the following format: Authorization: Token {token}
The token itself can be obtained by logging in to the web application, going to "My Preferences", and clicking on the "Authentication Token" tab. Alternatively, a token can be obtained using Basic authentication against the “Me” endpoint as described above. These tokens may be subject to invalidation for other reasons, but won't expire solely based on time. Tokens can also be manually invalidated and regenerated using the “My Preferences” page or the “Me/ResetAuthToken” endpoint.
Example of Token Authentication:
The example requests above will return various information including the API token you can use to make subsequent requests to other endpoints. For example, get a list of people from your ClickTime account by making the request below, substituting "API_TOKEN" with your actual API token you received from the request above.
curl -X GET \
https://api.clicktime.com/v2/users \
-H 'Authorization: Token API_TOKEN' \
All requests should include an appropriate Content-Type header. Currently the only supported content type is application/json , resulting in the following header:
Content-Type: application/json
Some requests make use of dates, either in the URL or in the body of a POST/PATCH request. In order to guarantee compatibility, all dates should be in the format YYYY-MM-DD (e.g. 2018-05-22).
Resource IDs will be in the format of a modern entity scramble (starting with a 4), but the legacy short scramble IDs (starting with a 2) are also available where indicated by the documentation. Simply add CTLegacyScramble=true to the request query parameters to access the LegacyID field. These legacy ID values will be deprecated in the future but, for now, are included to help migrate from older API versions.
Some endpoints have a verbose mode which returns additional fields and related resources, but which may take longer to execute. The endpoints with a verbose mode, and which additional fields are available, are indicated in the documentation. Clients can access verbose properties by adding Verbose=true to the request query parameters.
It is possible to filter the results on endpoints that return a list of resources. This can make it easier to process the results if the client is only looking for specific resources, and it can also speed up the response. The documentation indicates which endpoints support which filters. These filters all operate as query parameters:
?IsActive=true
All filters accept multiple values, which can be passed in by using multiple query parameters with the same name:
?TimeEntryID=4abc&TimeEntryID=4lmno&TimeEntryID=4xyz
For parameters which only support a specific list of values, you can check the model definition elsewhere in the documentation to see a list of available values. For example, if you are querying a report that can be filtered by TimesheetStatuses, check the model definition for GET /Timesheets to see a list of valid statuses.
Lists of result objects will be returned with a default page size of 100 records and a maximum of 1000. There are, however, a few endpoints that have a lower limit and “report” endpoints typically have larger limits. To access subsequent pages of results or to alter the number of records per page, clients can use the offset and limit query parameters. limit sets the number of resources returned, and offset defines how many results to skip. The correct value for offset is easy to calculate by multiplying the limit by the page number minus one:
limit * (page - 1)
The count parameter will show how many results there are in total so it is possible to calculate how many pages of results to expect.
Several endpoints have different defaults due to performance restrictions or expectations of how the endpoint is to be used. For example, GET /TimeEntries has a maximum page size of 100 while the GET /Reports/Time endpoint has a default page size of 2,500.
The sort order of result sets is not configurable in the REST API v2 at this time.
Too many requests in a short space of time will trigger the API's throttling mechanism. This mechanism acts as a basic defense against denial of service attacks. The current rate for the REST API v2 is 50 requests in 15 seconds. The time limit is a rolling limit, so if the client stops making requests they will rapidly fall back below the threshold. When triggered, the throttling mechanism will return a simple error response with a 429 status code.
In addition to the global throttle, the GET /TimeEntries endpoint has a more restrictive throttling limit of 10 requests in 5 seconds. People looking to get large amounts of time entry data are encouraged to use the GET /Reports/Time endpoint.
All parts of a batch call are subject to the global throttling limit. The number of requests logged will include the batch request itself and all its parts, which means that a batch request containing 49 parts will succeed (1 + 49 = 50), but a batch request containing 50 parts would fail for the last part (1 + 50 = 51).
All API responses are in standardized formats. We wrap all responses (both successes and errors) in a standard body that ensures a consistent response format and allows for the return of more sophisticated error messaging, metadata, paging, and links. The structure of this response body is as follows:
{
"data": {} or [],
"errors": [],
"jsonapi": {},
"meta": {},
"page": {
"count": 400,
"limit": 100,
"links": {
"first": "",
"last": "",
"next": "",
"previous": "",
"self": ""
}
"offset": 0
}
}
The data element contains a single object or a list of objects representing the requested resources. For example if you requested a list of Users, the data element will contain that list.
The errors element contains a list of errors or partial failures associated with your request. All error responses should be returned in the same format as documented and with meaningful status codes. Errors specific to each endpoint are documented in the detailed documentation, but these do not include a number of common error responses that may occur on many endpoints (e.g. 400, 401, 403, and 404 status codes). An error may represent a complete failure to process the request, in which case the requestor will receive an error status code and the details of that error will be listed in errors. An error may also represent a partial failure in which, for example, certain parts of your request may have been ignored. In this less common scenario, the requestor may receive a success status code but relevant error messaging will still be relayed in the errors list.
The jsonapi element may contain metadata about the API itself (versioning, copyright info, etc.)
The meta element may contain metadata specific to the response, such as warnings about properties that weren't or couldn't be updated.
The page element contains pagination data about the response. It details the count of how many results there are in total, the offset from the first result, and the limit of how many results you're getting per response. It also contains a links object, which provides absolute links to the first page of results, the last, the next, and the previous, as well as a link to the current page. In cases where only a single resource has been requested, or a resource has been created, only the self link will be populated. Similar paging data are also available from the response headers (see below).
A successful response may also contain no body at all if no data were requested (e.g. when deleting a resource), in which case the response will carry a 204 status code.
In cases where a resource has been created, the response will include a Location header containing the complete URI of the new resource. In cases where a list of objects is returned, the response will include a Link header containing links to the first and last page of results by way of the offset and limit query parameters.
Detailed documentation of the API's endpoints are available. The documentation for each endpoint includes:
- request models (where applicable)
- request validation requirements (where applicable)
- requirements for user permissions and company settings
- response models
- possible response status codes
- example response bodies
The responses for each endpoint include a link to the example value and the response model which allows you to toggle back and forth between them. The response model is especially important as it details all available fields, their data types, their validation requirements, what permissions you need to view them, and in some cases the set of permissible values.
The batch endpoint is designed to enable the concatenation of multiple API requests to any normal endpoint, execute them in series, and receive multiple responses in a single HTTP request. This endpoint is particularly useful in scenarios where network connectivity is a concern or issue, as it reduces the number of HTTP requests needed.
Important Note: This endpoint is not intended for bulk updates or actions. It should be used specifically for situations where minimizing network requests is necessary to avoid potential race conditions or connectivity problems. For most other use cases, standard API requests should be sufficient.
Please Note: The Batch endpoint requires the use of CRLF vs. LF in line endings.
When using a programmatic approach to hit the endpoint, we can make sure that the newline token used is CRLF (\r\n
) instead of LF (\n
) in the program. Using a tool like postman, the simplest way to ensure this is to add the following to the Pre-request Script tab:
const crlfBody = pm.request.body.toString().replace(/\n/g, '\r\n');
pm.request.body.update(crlfBody);
In order to make a batch request:
- Configure your REST client to make a POST request to /v2/$batch
- Set the Authorization header as usual.
- Set the content type to multipart/mixed and include a boundary. This boundary should be long and random such as
Content-Type: multipart/mixed;
boundary="dj8bjmwejx9h4j2zwbgawzmsqy930poik9pm" - Set the following additional headers:
* Expect: 100-continue
* Connection: Keep-Alive
* Cache-Control: no-cache - Populate the body of the request with HTTP requests separated by the boundary chosen above. Each HTTP request can have its own headers and call different endpoints using different methods. Each boundary must be prefixed with two dashes, except for the last which must also be suffixed with two dashes to indicate the end of the batch request. For example:
--dj8bjmwejx9h4j2zwbgawzmsqy930poik9pm
Content-Type: application/http; msgtype=request
POST /v2/TimeOffRequests/{timeOffRequestID}/Actions?comment=Nah
HTTP/1.1
Host: api.clicktime.com
Content-Type: application/json; charset=utf-8
{"Action": "Reject"}
--dj8bjmwejx9h4j2zwbgawzmsqy930poik9pm
Content-Type: application/http; msgtype=request
GET /v2/Users HTTP/1.1
Host: api.clicktime.com
Content-Type: application/json; charset=utf-8
--dj8bjmwejx9h4j2zwbgawzmsqy930poik9pm
Content-Type: application/http; msgtype=request
DELETE /v2/Jobs/{jobID} HTTP/1.1
Host: api.clicktime.com
Content-Type: application/json; charset=utf-8
Please note the white space seen here is required at the end of the message
--dj8bjmwejx9h4j2zwbgawzmsqy930poik9pm--
For more detail on multipart requests, see W3C's specification for The Multipart Content-Type.
The API will respond with a multipart HTTP response where each part will have its own headers (including status code) and be delineated by the same boundary as the request. Each part of the request can thus succeed or fail independently of the others, and a response may contain both success and error status codes.
Batch API requests are executed in series and respect the global throttling limits. See the throttling section above for details of how throttling applies to the use of this endpoint.
Known Issues/Limitations, Helpful Tips and Custom Fields
The following are known limitations with the REST API v2:
- Sub-jobs are not currently supported on the TimeEntries endpoints
- DCAA is not supported on the TimeEntries and Timesheets endpoints
- A person can only be created with the "standard" or "manager" security level. Creating Administrators is not currently supported via the API
- When a new person is created with the API, an invitation email is not sent to the newly added person (Read how to send the Welcome Email to any new users who have not yet signed in)
- The security level cannot be modified for an existing person
- Authentication is not yet possible via single sign-on (SSO)
You may receive different responses when asking for a particular object (such as a Job) depending on how it is requested:
- For example, if someone makes a request for the “GET /Jobs/{jobID}” endpoint and the jobID provided is not valid, then a 404 error response code is returned.
- Alternatively, if the request is made to the “GET /Jobs/?ID={jobID}” endpoint, thus the jobID is being passed in as a filter, if the jobID provided is not valid, a 200 success response is returned but with an empty “data” element because, using the provided filter, no data was found.
When a custom field associated with an object (e.g. job, client, task, user etc.) is configured as a drop-down list, the custom field values submitted through the API must match identically to a defined drop-down list value (including capitalization). For example, if a custom field's drop-down list includes "London" as an option, setting that custom field on an object to "london" without the capital "L" will result in a custom field exception error.
Comments
0 comments
Article is closed for comments.