Clockbook Guide
Introduction
By using Clockbook REST-based API, you can push and pull data to and from Clockbook, and integrate it with other systems. Feel free to post any questions you have on Stack Overflow with the Clockbook tag, or contact us if something is not working properly.
To get reports via API, you're going to have to use the base endpoint for reports (which is different from the one for manipulating other objects).
Authentication
All your requests should include "X-Api-Key" in request header, containing your API key.
If your workspace is on a subdomain (eg. something.clockbook.me), you'll need to generate a new API key in your Profile Settings that will work just for that workspace.
If you're a self-hosted user, you'll have to use a different API base endpoint: "https://yourcustomdomain.com/api" and "https://yourdomain.com/reports" (you can find exact endpoints when you go to "https://youdomain.com/web/boot").
Rate limiting
There's a rate limit of 10 requests per second. If you get over the limit, you'll get "Too many requests" error.
Webhooks
Webhooks can notify your app when something happens in Clockbook. You can access webhooks from the bottom of your Profile settings
Only workspace admins can create webhooks. Only the user who created the webhook can see and modify it. Each user can have up to 10 webhooks per workspace, and a workspace can have 100 in total
You can see logs of sent webhooks by clicking on a webhook you've created. There you can send a test webhook. Logs older than 7 days are deleted.
You can find your webhook's signing secret by clicking on the webhook's eye icon Webhooks page (or when you open edit screen of the webhook). Then, to verify the webhook with the signing secret, compare it with the "Clockbook-signature" value in the response header.
You can send "Action-Metadata" parameter via API request header, and its value will be passed along by the webhook event it triggered. Example: You can send "update time entry" request and pass along "Action-Metadata: MyRequestId123" in the header, and when the "time entry updated" webhook is triggered, you'll receive "Action-Metadata: MyRequestId123" in the webhook so you can avoid endless update loop.
To test and debug webhooks, you can use an online service like Request Catcher.
Available webhooks
- Timer started/stopped (me/anyone)
- Time entry created manually/updated/deleted (me/anyone)
- Client/project/task/tag created on workspace
Client
Response Content-Types: /
Response Example (200 OK)
[
{
id: "5b1e52ff0cb8792ed75992c1",
name: "Client X",
workspaceId: "5c0fe3290cl84304845dbf1f",
archived: "false",
},
];
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
Find clients on workspace
archived: boolean | If true, you'll get only archived clients. If false, you'll get only active clients |
---|---|
Still | renders |
1 | 2 |
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
Add a new client to workspace
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
Update client
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
Delete client
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
Project
Emphasis, aka italics, with asterisks or underscores.
Strong emphasis, aka bold, with asterisks or underscores.
Combined emphasis with asterisks and underscores.
Strikethrough uses two tildes. Scratch this.
Get all projects on workspace
Response Content-Types: /
Response Example (200 OK)
[
{
"id": "5e4e42156fe9056cfb00252",
"name": "Project",
"hourlyRate": null,
"clientId": "",
"workspaceId": "5e4e38caq7668c16662b303a",
"billable": true,
"memberships": [
{
"userId": "5a0ab5acb2d987125438b60f",
"hourlyRate": null,
"targetId": "5e4e38f156fe9056cfb00252",
"membershipType": "PROJECT",
"membershipStatus": "ACTIVE"
}
]
"color": "#4CAF50",
"estimate": {
"estimate": "PT0S",
"type": "AUTO"
}, // Legacy field, same info as timeEstimate
"archived": false,
"duration": "PT0S",
"clientName": "",
"note": "",
"template": false,
"public": false,
"costRate": null,
"budgetEstimate": null,
"timeEstimate": {
"estimate": "PT0S",
"type": "AUTO",
"resetOption": null,
"active": true
}
}
]
Find project by ID
Response Content-Types: /
Response Example (200 OK)
{
"id": "5e4e42156fe9056cfb00252",
"name": "Project",
"hourlyRate": null,
"clientId": "",
"workspaceId": "5e4e38caq7668c16662b303a",
"billable": true,
"memberships": [
{
"userId": "5a0ab5acb2d987125438b60f",
"hourlyRate": null,
"targetId": "5e4e38f156fe9056cfb00252",
"membershipType": "PROJECT",
"membershipStatus": "ACTIVE"
}
]
"color": "#4CAF50",
"estimate": {
"estimate": "PT0S",
"type": "AUTO"
}, // Legacy field, same info as timeEstimate
"archived": false,
"duration": "PT0S",
"clientName": "",
"note": "",
"template": false,
"public": false,
"costRate": null,
"budgetEstimate": null,
"timeEstimate": {
"estimate": "PT0S",
"type": "AUTO",
"resetOption": null,
"active": true
}
}
Add a new project to workspace
Request Content-Types: application/json
Request Example
{
"name": "My API Project",
// OPTIONAL
"clientId": "",
"isPublic": "false",
"color": "#f44336",
"note": "This is project's note",
"billable": "true",
"public": false
}
Response Content-Types: /
Response Example (201 Created)
{
"archived": "false",
"billable": "true",
"clientId": "",
"clientName": "",
"color": "string",
"duration": "PT0S",
"estimate": {
"estimate": "PT0S",
"type": "MANUAL"
}, // Legacy field, same info as timeEstimate
"hourlyRate": {
"amount": "0",
"currency": "USD"
},
"id": "5b1e6b160cb8793dd93ec120",
"memberships": [
{
"hourlyRate": {
"amount": "10",
"currency": "USD"
,
"membershipStatus": "ACTIVE",
"membershipType": "PROJECT",
"targetId": "5b1e6b160cb8793dd93ec120",
"userId": "5a9e9a39b079874a74cfa980"
}
}
],
"name": "My Api Project",
"public": false,
"costRate": null,
"budgetEstimate": null,
"timeEstimate": {
"estimate": "PT0S",
"type": "AUTO",
"resetOption": null,
"active": true
},
"workspaceId": "5b152d9b0cb8797f86cbe14f",
}
Tag
Endpoints for manipulating TAG resource
Find tags on workspace
Path
GET / workspaces / { workspaceId } / tags;
REQUEST PARAMETERS
name: string in query | If provided, tags will be filtered by name. |
---|---|
archived: boolean in query | If true, you'll get only archived tags. If false, you'll get only active tags. |
page: integer default: 1 in query | page |
| page-size: integ
| is-active:boolean
er
default: 50 in query | page-size |
RESPONSES
200 OK OK
401 Unauthorized Unauthorized
403 Forbidden Forbidden
404 Not Found Not Found
Response Content-Types: /
Response Example (200 OK)
[
{
id: "5a7c5d2db079870147fra234",
name: "Tag 1",
workspaceId: "5g3g57bt0cb2548e22e6l9cd",
archived: "false",
},
];
Add a new tag to workspace
Request Content-Types: application/json
Request Example
{
"name": "Tag 1"
}
Response Content-Types: /
Response Example (201 Created)
{
"id": "5a7c5d2db079870147fra234",
"name": "Tag 1",
"workspaceId": "5g3g57bt0cb2548e22e6l9cd"
}
Update tag
PATH
PUT / workspaces / { workspaceId } / tags / { tagId };
RESPONSES
200 OK OK
201 Created Created
401 Unauthorized Unauthorized
403 Forbidden Forbidden
404 Not Found Not Found
Delete tag
PATH
DELETE / workspaces / { workspaceId } / tags / { tagId };
RESPONSES
200 OK OK
204 No Content Content
400 Bad Request Bad Request
401 Unauthorized Unauthorized
403 Forbidden Forbidden
404 Not Found Not Found
Task
Endpoints for manipulating TASK resource
Response Content-Types: /
Response Example (200 OK)
[
{
"assigneeIds": ["593e40aab0798735d0392a2d"],
"estimate": "PT0S",
"id": "5b1e6b160cb8793dd93ec120",
"name": "Task 1",
"projectId": "5b1667790cb8797321f3d664",
"status": "ACTIVE" (Status: ACTIVE, DONE)
}
]
Find tasks on project
PATH
GET / workspaces / { workspaceId } / projects / { projectId } / tasks;
REQUEST PARAMETERS
is-active: boolean in query | If provided and true, only active tasks will be returned. Otherwise only finished tasks will be returned. |
---|---|
name: string in query | If provided, tasks will be filtered by name. |
page: integer default: 1 in query | page |
page-size: integer default: 50 in query | page-size |
RESPONSES
200 OK OK
401 Unauthorized Unauthorized
403 Forbidden Forbidden
404 Not Found Not Found
Find task on project by ID
PATH
GET /
workspaces /
{ workspaceId } /
projects /
{ projectId } /
tasks /
{ taskId };
RESPONSES
200 OK OK
401 Unauthorized Unauthorized
403 Forbidden Forbidden
404 Not Found Not Found
Add a new task on project
PATH
POST /workspaces/{workspaceId}/projects/{projectId}/tasks
RESPONSES
200 OK OK
400 Bad Request
Task with that name already exists
on project, or specified project
doesn't exist
401 Unauthorized Unauthorized
403 Forbidden Forbidden
404 Not Found Not Found
Time entry
Endpoints for manipulating TIMEENTRY resource
Get your time entries on workspace
Gets a time entry for specified user on workspace. Filters can be applied as query parameters listed below
Response Content-Types: /
Response Example (200 OK)
[
{
"billable": "true",
"description": "Writing documentation",
"id": "5b0fdf2a0cb87904845dfer5",
"isLocked": "false",
"projectId": "5b1667790cb8797321f3d664",
"tagIds": [
"5a7c5d2db079870147fra234"
],
"taskId": "5b1e6b160cb8793dd93ec120",
"timeInterval": {
"duration": "PT1M4S",
"end": "2018-06-12T14:01:41Z",
"start": "2018-06-12T14:00:37Z"
},
"userId": "6h1e49bf0cb8790e43d6c9ab",
"workspaceId": "5g3g57bt0cb2548e22e6l9cd"
},
"customFields": [
{
"customFieldId" : "5b1e6b160cb8793dd93ec120",
"timeEntryId" : "5c5bda4fb079871c518b6f07",
"value": "San Francisco",
"name": "Location"
}
]
]
Line Breaks
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a separate paragraph.
This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the same paragraph.