Below, we provide a step-by-step guide on how to synchronize employees from your system to TaskTime.
Internal or External.Note: Skip this step if you only manage internal employees.
For external employees (e.g., self-employed or ZZP individuals), it's essential to associate them with a hireCompanyReference before any insert or update actions.
If multiple employees are linked to one hire company:
hireCompanyReference for these external employees.If dealing with a self-employed individual (ZZP):
Once you have the reference, link the hireCompanyReference to your external employees as delineated in Step 2.
Pro-tip: Make use of a distinctive prefix for these fictitious email addresses. It aids us in swiftly pinpointing and erasing them from our records.
/
Make sure your IP address is whitelisted. Go to https://tasktime.eu:8800/api/myIP/ , and send the networkIP to TaskTime support.
The collection of API’s listed below all requires an API-Key in order to successfully retrieve requested data from the Data Service.
The key “api-key” needs to be applied in the headers of the request.
"headers": {
"api-key":"API KEY HERE"
}
All the API’s listed are relative to:
https://tasktime.eu:8800/api
So for example a full path api url might be: https://tasktime.eu:8800/api/read/employees/list/
| API | Type | Method | Url | Status |
|---|---|---|---|---|
| List of Employees | Read | GET | /read/employees/list/ | Live |
| Update or Insert Employees | Sync | POST | /sync/employee/ | Live |
| List of Relations, Locations and Departments | Read | GET | /read/relations/list/ | Live |
| List of projects | Read | GET | /read/projects/list/ | Live |
| Assign professional too a slot | Update | POST | /update/projects/assignToSlot/ | Live |
| List of Hire Companies | Read | GET | /read/hireCompany/list/ | Live |
| Update or Insert Hire Companies | Sync | POST | /sync/hireCompany/ | Live |
| Get payment data with ORT | Read | POST | /read/payment/ | Live |
| Get totals data with ORT | Read | POST | /read/totals/ | Live |
| Status | Meaning |
|---|---|
| Local Dev | This endpoint is in development and so not on production yet. |
| Local Done | This endpoint is done in development, but not yet released to production. |
| Live | This endpoint is released and ready for use on production |
\
| URL | Action |
|---|---|
| https://tasktime.eu:8800/api/read/employees/list/ | GET |
This is an example of the response on a 200-OK status. The employees are separated in ==Internals== and ==Externals==.
Remind the “thirdPartyID”, if this is null, the employee is not synced yet with third party software. You can update the thirdPartyID with the sync endpoint.
{
"result": [
"internals": [{
"mailAddress": String,
"activated": Boolean,
"reference": String
"mobile": String,
"createdOn": String,
"firstName": String,
"lastName": String,
"initials": String,
"gender": String,
"dayOfBirth": String,
"job": String,
"insurance": String,
"polisNumber": String,
"bankAccount": String,
"driversLicense": Boolean,
"ssn": String,
"address": String,
"zipcode": String,
"city": String,
"hireCompanyReference": null,
"emergencyName": null or String,
"emergencyTelephone": null or String,
"emergencyCity": null or String,
"comment": String,
"emergencyAddress": null or String,
"thirdPartyID": null or String
}],
"externals": [{
"mailAddress": String,
"activated": Boolean,
"reference": String
"mobile": String,
"createdOn": String,
"firstName": String,
"lastName": String,
"initials": String,
"gender": String,
"dayOfBirth": null,
"job": String,
"insurance": null,
"polisNumber": null,
"bankAccount": null,
"driversLicense": null,
"ssn": null,
"address": String,
"zipcode": String,
"city": String,
"hireCompanyReference": String,
"emergencyName": null,
"emergencyTelephone": null,
"emergencyCity": null,
"comment": String,
"emergencyAddress": null,
"thirdPartyID": null or String
}]
]
}
\
| URL | Method |
|---|---|
| https://tasktime.eu:8800/api/read/relations/list/ | GET |
This endpoint provides a list of all customers. Within each customers all the locations. And within each location all departments.
Output:
{
"result": [
{
"customer": STRING, // name of the relation
"reference": STRING,
"address": STRING,
"city": STRING,
"contactPerson": STRING,
"mailAddress": STRING,
"customerNumber": STRING, // NL: "klantnummer"
"invoiceAddress": STRING,
"invoiceDepartment": STRING,
"invoiceZipcode": STRING,
"invoiceCity": STRING,
"kvk": STRING,
"mobile": STRING,
"organisationType": STRING, // "bv", "eenmanszaak", "nv"
"telephone": STRING,
"zipcode": STRING,
"country": STRING,
"thirdPartyID": STRING or null,
"locations": [
{
"location": STRING,
"reference": STRING,
"locationNumber": STRING,
"address": STRING,
"zipcode": STRING,
"city": STRING,
"contactPerson": STRING,
"mailAddress": STRING,
"telephone": STRING,
"mobile": STRING,
"costCenter": STRING, // NL: "kostenplaats"
"thirdPartyID": STRING or null,
"departments": [{
"department": STRING,
"reference": STRING,
"costCenter": STRING,
"thirdPartyID": STRING or null,
}]
},
]
},
]
}
/
| URL | Action |
|---|---|
| https://tasktime.eu:8800/api/read/projects/list/ | GET |
Explanation part - use relations or projects
The projects in the
relationsArray is grouped in relations and locations. And the sub-projects inside the locations.The projects in the
projectsArray is not grouped in relations and locations. This is a raw output of all projects.
The subprojects are grouped in the projects.
{
"result": {
"relations": [],
"projects": []
}
}
{
"relations": [
{
"relation_reference": String
"locations": [
{
"location_reference": String,
"projects" [
... see project model
]
}
]
}
]
}
{
"projects": [
{
"reference": String,
"created_on": String,
"project_name": String,
"project_description": String,
"project_work": String,
"relation_reference": String,
"location_reference": String,
"department_reference": String,
"period_from": String,
"period_to": String,
"project_status": String,
"cost_center": String,
"weekly_hours_min": Decimal,
"weekly_hours_max": Decimal,
"contact_person_name": String,
"contact_person_role": String,
"contact_person_telephone": String,
"contact_person_mail": String,
"signing_person_name": String,
"signing_person_role": String,
"signing_person_telephone": String,
"signing_person_mail": String,
"approver_person_name": String,
"approver_person_role": String,
"approver_person_telephone": String,
"approver_person_mail": String,
"invoice_mail": String,
"rate_per_hour": Decimal,
"ort_branche_reference": String,
"btw_type": String,
"btw_percentage": Decimal,
"travel_cost_km": Decimal,
"travel_cost_money": Decimal,
"travel_cost_type": String,
"slots": [
{
"reference": String,
"project_reference": String,
"employee_reference": String,
"slot_number": Integer,
"is_assigned": Boolean,
"btw_percentage": Decimal,
"btw_type": String,
"job_name": String,
"ort_branche_reference": String,
"position": String,
"position_rank": Integer,
"rate_per_hour": Decimal,
"self_planning": Boolean,
"travel_cost_km": Decimal,
"travel_cost_money": Decimal,
"travel_cost_type": String,
"work_hours_hours_from": Decimal,
"work_hours_hours_to": Decimal,
"work_hours_type": String
}
],
"subprojects": [
... same as project
]
}
]
}
/
| URL | Action |
|---|---|
| https://tasktime.eu:8800/api/update/projects/assignToSlot/ | POST |
/
{
"projectReference": String,
"employeeReference": String,
"slotReference": String
}
200 OK
\
| URL | ACTION |
|---|---|
| https://tasktime.eu:8800/api/read/hireCompany/list/ | GET |
{
"result": [
{
"address": String,
"archived": Integer
"city": String,
"comment": String, // comment about the hire company
"company": String, // company name
"contactperson": String,
"customerNumber": String, // klantnummer
"emailaddress": String,
"iban": String,
"kvk": String,
"mobile": String,
"organisation_type": String, // "eenmanszaak", "vof", "cv", "bv", "nv", "vereniging", "stichting"
"paymentCondition": {
"days": Integer or null
},
"postcode": String,
"reference": String,
"telephone": String,
"thirdPartyID": String or null
"vatNumber": String // BTW nummer
}
]
}
About thirdPartyID
When this is null, it means it is created by TaskTime and not synced yet with third party software.
\
With this endpoint you will retrieve all ORT data and other totals that are needed to payout an employee.
| Url | Action |
|---|---|
| https://tasktime.eu:8800/api/read/payment/ | POST |
example:
{
"from": "2021-02-03",
"to": "2021-02-06",
"employeeReference": "7EH1MAHacQKxqRlUMp4BVyPEqG72H71582463916014"
}
| Key | Value requirement |
|---|---|
| from | The start date, in format yyyy-mm-dd |
| to | The end date, in format yyyy-mm-dd |
| employeeReference | Existing employee reference |
The from and to should have a maximum range of 31 days.
The maximum response time is ± 4000ms.
The response gives back two parental keys: groupedByCostCenter and withoutCostCenter.
Example of response:
{
"groupedByCostCenter": [
{
"costCenter": "K458712",
"ortTotals": [
{
"percentage": 138,
"duration": 7
},
{
"percentage": 149,
"duration": 1
}
],
"totalHours": 8,
"ortDays": [
{
"date": "2021-02-03",
"ort": [],
"totalHours": 0
},
{
"date": "2021-02-04",
"ort": [],
"totalHours": 0
},
{
"date": "2021-02-05",
"ort": [],
"totalHours": 0
},
{
"date": "2021-02-06",
"ort": [
{
"percentage": 138,
"duration": 7
},
{
"percentage": 149,
"duration": 1
}
],
"totalHours": 8
}
]
}
],
"withoutCostCenter": {
"ortDays": [
{
"date": "2021-02-03",
"ort": [],
"totalHours": 0
},
{
"date": "2021-02-04",
"ort": [],
"totalHours": 0
},
{
"date": "2021-02-05",
"ort": [],
"totalHours": 0
},
{
"date": "2021-02-06",
"ort": [
{
"percentage": 138,
"duration": 7
},
{
"percentage": 149,
"duration": 1
}
],
"totalHours": 8
}
],
"ortTotals": [
{
"percentage": 138,
"duration": 7
},
{
"percentage": 149,
"duration": 1
}
],
"totalHours": 8
}
}
}
\
| URL | Action |
|---|---|
| https://tasktime.eu:8800/api/sync/employee/ | POST |
This endpoint inserts or updates employees. You can send for example 25 internal employees and 10 external employees. They will all be processed.
During iteration of each employee this endpoint will detect if it should be updated or inserted.
You can send multiple internal and external employees.
Even if you send a single employee, make sure the object of that employee is in an Array (internals or externals) like in the below example.
Remind the “thirdPartyID”, you have to fill in a reference where you can recognize with the third party software employee record. For example you can fill in here the “registratienummer” from the other software.
All keys per employee as exampled below are REQUIRED. Some might have an empty string or null, but the keys should be there.
:::
{
"employees": {
"internals": [{
"mailAddress": String (valid mail format and lowercase),
"activated": Boolean,
"reference": null or String (See About Reference below doc),
"mobile": String (non-empty string, 10 digits string starts with 06),
"firstName": String (non-empty string, alphabetic with space, no special chars),
"lastName": String (non-empty string, alphabetic with space, no special chars),
"initials": String (non-empty string, alphabetic, no special chars),
"gender": String ("male" or "female", lowercased),
"dayOfBirth": String ("yyyy-mm-dd" formatted, and valid date)
"insurance": String (non-empty or empty string),
"polisNumber": String (non-empty or empty string),
"bankAccount": String (non-empty or empty string, alphanumeric only),
"driversLicense": Boolean,
"ssn": String (non-empty or empty string, alphanumeric and space),
"address": String (non-empty string, alphanumeric and space),
"zipcode": String (non-empty string, alphanumeric and space),
"city": String (non-empty string, alphanumeric and space),
"thirdPartyID": String or null (non-empty string, alphanumeric only),
"comment": String (non-empty or empty string),
"emergencyName":String (non-empty or empty string, alphanumeric and space),
"emergencyTelephone":String (non-empty or empty string, alphanumeric and space),
"emergencyAddress":String (non-empty or empty string, alphanumeric and space),
"emergencyCity":String (non-empty or empty string, alphanumeric and space)
}],
"externals": [{
"mailAddress": String (valid mail format and lowercase),
"activated": Boolean,
"reference": null or String (See About Reference below doc),
"mobile": String (non-empty string, 10 digits string starts with 06),
"firstName": String (non-empty string, alphabetic with space, no special chars)
"lastName": String (non-empty string, alphabetic with space, no special chars),
"initials": String (non-empty string, alphabetic, no special chars),
"address": String (non-empty string, alphanumeric and space),
"zipcode": String (non-empty string, alphanumeric and space),
"city": String (non-empty string, alphanumeric and space),
"thirdPartyID": String or null (non-empty string, alphanumeric only),
"hireCompanyReference": String (non-empty string, alphanumeric only)
}]
}
}
Following error codes may response.
When an error occures, other than 200 OK, the entire process will be stopped. No employee will be processed at all.
:::
| Error code | Error type | Explained |
|---|---|---|
| 200 | OK | See “Response OK” section below. |
| 400 | Bad Request | Missing mandatory parental key in body, you will retrieve which key |
| 422 | Unprocessable Entity | If a key or value of a key inside employee object is invalid and can not process the entire request. You will retrieve a list of employees that having these missing requirement. |
| 500 | Server error | This should not happen at all. You will retrieve the error response with more information if this occurs |
If the error code is 200 OK, you will receive a report of what the endpoint achieved.
For example the output will be:
{
"numberOfInserted": 25,
"numberOfUpdated": 10,
"processed": {
"inserted": [listOfEmployees],
"updated": [listOfEmployees]
}
}
For each employee that you want to update, you have to apply the correct reference that you can get from the list endpoint.
If you want to insert a new employee into tasktime, then there is no reference yet. So you can leave this blank by giving null. The key should be there, but just give it null.
After insert
The employee will get a reference created by TaskTime after inserted. You will mention the reference when you get the list of employees after you inserted new employee(s).
Validations
This endpoint will do checks for you.
If you want to create a new user, and the username (mailAddress) is already existing, and no reference is applied (null), then you will get a detailed error response back. It will tell you which employee need to have a reference / already existing.
Also it will check if you want to update, if the username is
correspondending with the reference. If not, you will get a detailed error response back about the conflict(s).
\
With this endpoint you are able to add or edit hire companies. A single or multiple.
If you provide a reference, you want to update an existing hire company in TaskTime.
If you provide a reference with null, you want to create a new hire company in TaskTime.
| Url | Action |
|---|---|
| https://tasktime.eu:8800/api/sync/hireCompany/ | POST |
All the keys are required.
You can apply single or multiple hire companies. Make sure you start with an ==array== hireCompanies. Even for a single hire company.
Even if you don’t have a reference for a hire company, because you want to create a new one, then provide null as a value.
{
"hireCompanies": [{
"address": String,
"postcode": String,
"city": String,
"mobile": String,
"telephone": String,
"company": String,
"comment": String,
"kvk": String,
"organisation_type": String (see About organisation type),
"reference": String or null (see About reference),
"contactperson": String,
"emailaddress": String (email address format),
"thirdPartyID": String (see About thirdPartyID)
}]
}
There is a fixed list of organisation types, which are:
Provide one of them and make sure it’s lowercased.
When you want to update a hire company, you have to provide the correspondending reference of that hire company. Which you can find in the endpoint of retrieve list of hire companies.
When you want to insert a new hire company, you have to give null as a reference.
This is a reference for yourself, which could be a reference to any identification of the third party software. For example “registratienummer” of that third party software. So you can see if this company is already synced or not, whether to update or insert into the third party software.
When it’s not synced yet, it will have null from the list.
So always fill in the thirdPartyID for your own logic.
Following error codes may response.
When an error occures, other than 200 OK, the entire process will be stopped. No hire company will be processed at all.
:::
| Error code | Error type | Explained |
|---|---|---|
| 200 | OK | See “Response OK” section below. |
| 400 | Bad Request | Missing mandatory parental key in body, you will retrieve which key |
| 422 | Unprocessable Entity | If a key or value of a key inside hire company object is invalid and can not process the entire request. You will retrieve a list of hire companies that having these missing requirement. |
| 500 | Server error | This should not happen at all. You will retrieve the error response with more information if this occurs |
If the error code is 200 OK, you will receive a report of what the endpoint achieved.
For example the output will be:
{
"numberOfInserted": 3,
"numberOfUpdated": 1,
"processed": {
"inserted": [listOfHireCompanies],
"updated": [listOfHireCompanies]
}
}
With this endpoint you will retrieve all shifts and totals data with ORT percentage and billable hours.
https://tasktime.eu:8800/api/read/totals/
POST
"headers": {
"api-key":"API-KEY-HERE"
}
{
"from": String,
"to": String
}
The from and to should have a maximum range of 31 days
| Key | Value type | Explanation |
|---|---|---|
| from | String | The start date of the period, format: YYYY-MM-DD |
| to | String | The end date of the period, format: YYYY-MM-DD |
The API will response with data of all the customers, locations and departments. And for each, all the shifts and totals.
{
"customers": [{
"customerReference": String, // reference to relation, use the List of relations API to match
"shifts": [], // all the shifts worked for this customer
"totals": [], // the totals of all shifts for this customer
"locations": [{
"locationReference": String, // reference to location, use the List of relations API to match
"shifts": [], // all the shifts worked for this location within this customer
"totals": [], // the totals of all shifts for this location within this customer
"departments": [{
"departmentReference": String, // reference to department, use the List of relations API to match
"shifts": [], // all the shifts worked for this department within this location
"totals": [], // all the shifts worked for this department within this location
}]
}]
}]
}
Within each customer, location or department, as described above, contains "shifts" array.
Here the specification of this array.
ORT Blocks inside each shift Each shift is exploded into ORT blocks. Here you can see how the ORT hours are built-up.
The pauseTimeInHours (unpaid break-time), will subtract the billingDurationInHours from the lowest ORT percentage blocks.
Sleeptime block excluded.
"shifts": [{ // Array
"id": String, // unique ID for this shift
"dataStringV2": String, // If anything of the shift changes, this string will be changed too
"date": String, // DD-MM-YYYY formatted, the start day of the shift
"startDateTime": String, // YYYY-MM-DD HH:mm formatted, the start datetime of the shift
"endDateTime": String, // YYYY-MM-DD HH:mm formatted, the end datetime of the shift
"shiftJob": String, // Jobs attached to a shift
"pauseTimeInHours": Float, // unpaid breaktime in hours
"employeeReference": String, // the reference for employee, use the read employees API to match
"employeeInternal": Boolean, // if this employee is internal or external
"travelDistanceKM": Int, // total travel distance between work and home and back
"travelDistanceCapKM": Int or null, // the applied travel km cap for this location
"travelDistanceWithCapIncludedKM": Int, // total travel distance with possible cap included calculated
"additionalTravelDistanceKM": Int, // any additional travel distance that the employee had to do
"shiftHours": Float, // total gross hours, might not be billable hours
"approved": Boolean, // shift approved by relation: this shift is accomplished by employee
"ortBlocks": [{ // array
"blockType": String, // worktime or sleeptime
"startDateTime": String, // YYYY-MM-DD HH:mm formatted, start of this shift block
"endDateTime": String, // YYYY-MM-DD HH:mm formatted, end of this shift block
"durationInHours": Float, // gross hours of this shift block
"ortPercentage": Int, // ORT percentage of this shift block
"billingDurationInHours": Float, // calculated billable hours, unpaid breaktime or partial sleeptime removed
"unpaidByPauseTimeInHours": Float or null, // on pauseTimeInHours, it might subtract (partial) from this block
}]
}]
Within each customer, location or department contains "totals" array.
Here the specification of this array.
"totals": [{
"billableHours": Float, // total billable hours, calculated by using the "billingDurationInHours" from ortBlocks array.
"travelKM": Int, // total travel distance from home to work and back, calculated by "travelDistanceWithCapIncludedKM" from ortBlocks array.
"numberOfShifts": Int, // total number of shifts
"ortPercentages": [{ // array
"ortPercentage": Int, // ORT percentage
"billableHours": Float, // Total billable hours for this ORT percentage
}]
}]