Are you using Harvest, Teamwork, JIRA, Asana, Toggl, … but missing some functionality like profits, revenues, etc…? Costlocker is now able to create and update projects via its API.
- Project API introduction
- Project items - personnel costs (activity, person, task), project expenses, discount, billing
- API shortcuts
- Demo - Import projects from Harvest
Updates
- April 2018: we’ve added project budgets
- September 2018: we’ve added no-budget
- January 2019: we’ve added person client rate
- April 2019: we’ve added recurring projects, progress and billable exceeded estimates
- August 2019: we’ve added multi-currency
Project API introduction
We tried to unify the project structure as much as possible. If you’re familiar with /api-public/v2/projects/ endpoint it should be simple to execute any operation with project.
Project detail
Basic project information is available in the standard json format.
More advanced concepts (personnel costs, billing, …) are defined in items
.
{
"id":"123456",
"name":"Website",
"client": "Google",
"dates":{
"date_start":"2017-03-20",
"date_end":"2017-05-20"
},
"state": "running",
"project_type": "standard",
"currency": {
"project": "EUR",
"json": "USD"
},
"recurring": {
"id": null,
"settings": null
},
"project_id": {
"id": null,
"is_generated": false
},
"tags":["Billable"],
"responsible_people": ["test@example.com"],
"budget": {
"type": "time_estimates.person_activity",
"client_rate": "activity",
"progress_type": null,
"bill_exceeded_estimates": false
},
"items":[]
}
Recurring projects
Read-only! Not editable in API. E.g. you can’t create a new recurring project in API.
- The
project_type
is one of: - The
recurring
contains more detailed info:id
is filled forstandard
projects created fromrecurring
projectsettings
is filledrecurring
projects, it’s not editable in API
Recurring project example
{
"id": 123,
"name":"Parent project",
"project_type": "recurring",
"recurring": {
"id": null,
"settings": {
"frequency": "monthly",
"date_start": "2019-01-01",
"date_end": null
}
},
"links": {
"project": "https://new.costlocker.com/api-public/v2/projects/123"
}
}
Standard project created from recurring project
{
"id": 456,
"name":"Child project",
"project_type": "standard",
"recurring": {
"id": 123,
"settings": null
},
"links": {
"project": "https://new.costlocker.com/api-public/v2/projects/456",
"recurring_project": "https://new.costlocker.com/api-public/v2/projects/123"
}
}
Other project settings
- The
state
is read-only, it can’t be updated. Use project’saction
to finish an running project or reopen an finished project. - The
project_id
configures custom project id. Useis_generated: true
if you’d like to use Auto ID.
Budget
- The
type
contains one of available project budgets - The
client_rate
specifies type of hourly rate (rate is specified in item’sactivity.hourly_rate
)activity
- one hourly rate for all people in an activityperson
- people can have different hourly rates in an activity, an person can even have different hourly rates in tasks
- The
progress_type
enables tracking project progress with time estimates.- Progress is available for budgets without estimates (timesheet, fixed price, no budget).
- Estimated hours are used only for tracking progress. Estimates don’t affect revenue.
- Available budgets:
time_estimates.person_activity
,time_estimates.activity
,no_budget
(ornull
)
- The
bill_exceeded_estimates
enables increasing project budget based on the estimated number of hours. Tracked hours are marked as billable even when stimated hours are exceeeded.
Items
Field items
are used for defining personnel costs, project expenses, billing and discount.
The returned item is always of the same format:
- The
item
containstype
and Costlocker ids - The item is described in remaining fields (typically, there is
<entity>_id
in theitem
and the detail in the<entity>
field) - The response after creating or updating projects contains only the
item
(you can use returned ids for storing mapping information) - The
action
is optional, theupsert
operation is used by default. You can use thedelete
action to delete any items
{
"items":[
{
"action": "upsert",
"item":{
"type":"expense",
"expense_id":"123457"
},
"expense":{
"description":"Invision",
"purchased":{
"total_amount":500,
"date":null
},
"billed":{
"total_amount":500
}
}
}
]
}
Personnel costs
You can define an activity, a person and a task. We recommend to create just leafs though. Activity budget represents an aggregation of personal budgets. The personal budget is an aggregation of tasks. This way, you can just create the leaf and the activity/person is upserted.
Activity
Every activity has a name and an hourly rate. The existing client rate is used if the hourly_rate
is missing.
If you create a new activity without an hourly rate, zero rate is used.
{
"item": {
"type": "activity",
"activity_id": 123456
},
"activity": {
"name": "Social media",
"hourly_rate": 100
}
}
Person
It is necessary to specify the email, names, role and salary for every new person. The role, salary and names are used only when creating a new person. An existing person is never updated!
{
"item": {
"type": "person",
"activity_id": 123456,
"person_id": 123456
},
"hours": {
"budget": 5
},
"activity": {
"name": "Social media",
"hourly_rate": 20
},
"person": {
"email": "manager@example.com",
"first_name": "Monthly",
"last_name": "Salary",
"role": "MANAGER",
"salary": {
"payment": "monthly",
"salary": 10000,
"hours": 160,
"date_start": "2017-02-01 10:00:00"
}
}
}
The same person definition can be used in responsible_people
field.
Task
Tasks are assigned to a person and activity. A parent can be referenced by ids in the item
or by a name/email in the relevant field. References are also described in shortcuts.
{
"item": {
"type": "task",
"activity_id": 123456,
"person_id": 123456,
"task_id": 123456
},
"hours": {
"budget": 20
},
"activity": {
"name": "Social media",
"hourly_rate": 20
},
"task": {
"name": "new task"
},
"person": {
"email": "employee@example.com",
"first_name": "Hourly",
"last_name": "Rate",
"role": "ADMIN",
"salary": {
"payment": "hourly",
"hourly_rate": 0
}
}
}
Project expenses
Partial updates are supported. Please see the example in billing.
{
"item": {
"type": "expense",
"expense_id": 123457
},
"expense": {
"description": "new description",
"purchased": {
"total_amount": 1000,
"date": "2017-05-15"
},
"billed": {
"total_amount": 500
}
}
}
Discount
Every project has one discount. No ids are used, there is only one amount that needs to be adjusted.
{
"item": {
"type": "discount"
},
"discount": {
"total_amount": 100
}
}
Billing
Be aware that revenue (personnel costs + project expenses - discount) cannot be smaller than billing.
{
"item": {
"type": "billing"
},
"billing": {
"description": "INV201705150001",
"total_amount": 900,
"date": "2017-05-15",
"status": "draft"
}
}
You can execute partial updates, such as changing the billing status without modifying the amount…
{
"item": {
"type": "billing",
"billing_id": 123456
},
"billing": {
"status": "sent"
}
}
Budgets
We support new budget types since April 2018:
type |
Description |
---|---|
time_estimates.person_activity |
Activity hourly rate * Person hours estimates |
time_estimates.activity |
Activity hourly rate * Activity hours estimate |
timesheet |
Activity hourly rate * Tracked hours |
no_budget |
All tracked hours are non-billable |
fixed_price.activity |
Activity fixed price |
fixed_price.project |
Project fixed price |
Below you can see what fields are required for each budget type with activity hourly rate. You can send for example person hours budget to timesheet budget, but we’ll ignore it (webhook would contain zero hours budget).
Required fields for person hourly rate:
You don’t have to worry about different client rate, if you create just leafs!
Person estimates (time_estimates.person_activity
)
Budget is defined in person
and activity
item.
Take a look at personnel costs.
{
"item": {
"type": "person",
"activity_id": 123456,
"person_id": 123456
},
"activity": {
"name": "Social media",
"hourly_rate": 20
},
"hours": {
"budget": 5
},
"person": "manager@example.com"
}
Activity estimates (time_estimates.activity
)
Budget is defined in activity
item:
{
"item": {
"type": "activity",
"activity_id": 123456
},
"activity": {
"name": "Social media",
"hourly_rate": 100
},
"hours": {
"budget": 20
}
}
Timesheet (timesheet
)
Budget is defined in activity
item:
{
"item": {
"type": "activity",
"activity_id": 123456
},
"activity": {
"name": "Social media",
"hourly_rate": 100
}
}
No budget (no_budget
)
Hourly rate or budget amount is ignored. Tracked time is never billed!
{
"item": {
"type": "activity",
"activity_id": 123456
},
"activity": {
"name": "Social media"
}
}
Activity fixed price (fixed_price.activity
)
Budget is defined in activity
item:
{
"item": {
"type": "activity",
"activity_id": 123456
},
"activity": {
"name": "Social media"
},
"budget": {
"total_amount": 2000
}
}
Project fixed price (fixed_price.project
)
Budget is defined in project
item:
{
"item": {
"type": "project"
},
"budget": {
"total_amount": 2000
}
}
Progress budget
Add hours budget if project progress is tracked with time estimates.
Add it to person item if you’re using time_estimates.person_activity
,
add it to activity item if time_estimates.activity
.
{
"hours": {
"budget": 20
}
}
Multi-currency
Project has one currency defined in currency.project
.
The second currency.json
avoids BC in API, since we had supported only one currency per company.
{
"currency": {
"project": "EUR",
"json": "USD"
}
}
Example
- main company currency is USD, but some projects are managed in EUR
- we’ve added an exchange rate
1USD = 0.9EUR
- project revenue is 900EUR (~1000USD)
Company currency
By default all responses have amounts in company currency, in our case it’s USD.
{
"currency": {
"project": "EUR",
"json": "USD"
},
"items": [
{
"item": {
"type": "project"
},
"budget": {
"total_amount": 1000
}
}
],
"links": {
"project": "https://new.costlocker.com/api-public/v2/projects/123",
"peoplecosts": "https://new.costlocker.com/api-public/v2/projects/123?types=peoplecosts",
"change_currency": "https://new.costlocker.com/api-public/v2/projects/123?currency=project"
}
}
Project currency - ?currency=project
Amounts are returned in project currency when query string ?currency=project
is used.
{
"currency": {
"project": "EUR",
"json": "EUR"
},
"items": [
{
"item": {
"type": "project"
},
"budget": {
"total_amount": 900
}
}
],
"links": {
"project": "https://new.costlocker.com/api-public/v2/projects/123?currency=project",
"peoplecosts": "https://new.costlocker.com/api-public/v2/projects/123?currency=project&types=peoplecosts",
"change_currency": "https://new.costlocker.com/api-public/v2/projects/123"
}
}
Updating projects
Same rules are applied for creating/updating projects.
We determine project currency from currency.project
and amounts currency from currency.json
.
Query string ?currency=project
is ignored!
API shortcuts
You can use shortcuts when creating a new project or experimenting with the API. This is an experimental feature for developers. If you don’t like it, you can use the standard formats returned by the API.
Shortcut | Full representation | Description |
---|---|---|
item |
item.type |
Item type definition |
activity |
activity.name |
Activity referenced by name |
person |
person.email |
Person referenced by email |
task |
task.name |
Task referenced by name |
hours |
hours.budget |
Hours budget |
client |
client.id or client.name |
Client referenced by id or name |
tag |
tag.id or rag.name |
Tag referenced by id or name |
Let’s say you want to create a new task for an existing person:
{
"name":"Shortcuts experiment",
"client":"Google",
"responsible_people":[
"existing-perso@example.com",
{
"email":"manager@example.com"
}
],
"tags":[
"social",
{
"name":"Billable"
}
],
"items":[
{
"item":"task",
"task":"new task",
"activity":"Social media",
"person":"existing-person@example.com",
"hours":5
}
]
}
Be aware that shortcuts are only used in requests.
A response always contains standard item
definition.
{
"id": "2707",
"items":[
{
"action":"upsert",
"item":{
"type":"task",
"activity_id":579,
"person_id":123456,
"task_id":"855"
}
}
]
}
Demo: Import projects from Harvest
We’ve built Harvest projects importer during development of the new API, try it at https://harvest.integrations.costlocker.com (source code).
Let us know if you’ve created similar application that connects Costlocker to a project management tool!
Did you find a mistake? Is something unclear or isn’t the code working? Help us to improve the article!