Base URL: https://tasktime.eu:8800
Format: JSON over HTTPS
Last updated: August 2026
This document is the reference for integrating with the TaskTime External API. It covers authentication, conventions, and every public endpoint: employees, hire companies, relations, shifts, projects, invoices and hour/payroll data.
Only endpoints that authenticate with an API key are documented here. Internal operations endpoints (deployment management, the internal document service) and the TaskSign signing-flow endpoints (which use per-signer signing keys instead of an API key) are intentionally not part of this reference.
Almost all endpoints require an API key in the request headers:
api-key: your-api-key-here
Content-Type: application/json
Authentication failures:
| Status | When |
|---|---|
400 Bad Request |
The api-key header is missing, or has an invalid format/length. |
401 Unauthorized |
The API key is unknown or not authorized. |
| Concept | Format |
|---|---|
| Date | YYYY-MM-DD (for example 2026-08-10) |
| Date-time | YYYY-MM-DD HH:mm (for example 2026-08-10 09:30) |
| Timezone | Europe/Amsterdam, unless stated otherwise |
| Reference | Unique TaskTime identifier of a record (alphanumeric string). Returned when you create or list records. |
thirdPartyID / thirdPartyShiftReference |
Your own identifier, stored on the TaskTime record so you can correlate both systems. |
| Money | Numbers with two decimals, currency EUR |
| Hours | Numbers in hours, decimals allowed (for example 7.5) |
All request bodies are JSON (Content-Type: application/json). A body that is not valid JSON is rejected with 400 Bad Request and the error Invalid JSON format.
Error responses have a consistent shape:
{
"error": "Short error label",
"message": "Human readable explanation of what went wrong"
}
Validation-heavy endpoints can include an extra key with the record that failed, for example employee (sync employees) or hireCompanyThatWentWrong (sync hire companies).
Note on status codes: the newer endpoints (relations, sync, payment, totals) use precise status codes such as
400,404,409and422. Some older endpoints (shifts, invoices, project slot assignment) return validation failures as HTTP500with the error labelMissing or invalid keys. Always inspect theerror/messagepayload, not only the status code.
The API has a built-in concurrency limiter that answers with 429 Too Many Requests when too many requests are open simultaneously. It is currently not enforced, but clients must handle 429 responses: wait for the previous request to finish, then retry.
For bulk endpoints (sync employees, sync hire companies, create shifts), send batches sequentially — wait for each request to finish before sending the next one.
| Method | Path | Description |
|---|---|---|
| POST | /api/sync/employee/ |
Create or update employees (bulk) |
| GET | /api/read/employees/list/ |
List all employees |
| POST | /api/sync/hireCompany/ |
Create or update hire companies (bulk) |
| GET | /api/read/hireCompany/list/ |
List all hire companies |
| POST | /api/create/relation/ |
Create a relation (customer) |
| POST | /api/create/location/ |
Create a location for a relation |
| POST | /api/create/department/ |
Create a department for a location |
| POST | /api/update/relation/ |
Update a relation |
| POST | /api/update/location/ |
Update a location |
| POST | /api/update/department/ |
Update a department |
| GET | /api/read/relations/list/ |
List relations with locations and departments |
| POST | /api/shifts/create |
Create shifts (assigned or open) |
| POST | /api/shifts/assign |
Assign shifts to professionals |
| POST | /api/shifts/read |
Read shifts by your own references |
| POST | /api/shifts/delete |
Delete shifts by your own references |
| GET | /api/read/projects/list |
List projects, slots and sub-projects |
| POST | /api/update/projects/assignToSlot |
Assign a professional to a project slot |
| POST | /api/invoices/byPeriod |
Invoices and collection specifications in a period |
| GET | /api/read/invoice/organisation/details/ |
Organisation details used on invoices |
| POST | /api/read/payment/ |
Payroll (ORT) data per employee per period |
| POST | /api/read/totals/ |
Worked hours and totals per relation/location/department |
Creates and updates internal and external employees in one batch. This is a full-record sync: send reference: null to create an employee, or the existing TaskTime reference together with the current mailAddress to update one.
POST /api/sync/employee/
Creating an employee also creates its account through TaskTime's regular employee creation flow. A newly created employee is deactivated immediately after creation when activated is false.
For batches larger than 50 employees, split the records into smaller requests and wait for each request to finish before sending the next one.
Body
Both arrays are optional, but at least one must be present. Empty arrays are allowed.
{
"employees": {
"internals": [
{
"mailAddress": "jane.doe@example.com",
"activated": true,
"reference": null,
"mobile": "0612345678",
"firstName": "Jane",
"lastName": "Doe",
"initials": "J",
"gender": "female",
"dayOfBirth": "1990-05-12",
"driversLicense": true,
"address": "Main Street 1",
"zipcode": "1234 AB",
"city": "Amsterdam",
"insurance": "Example Insurance",
"polisNumber": "POLIS100",
"bankAccount": "NL00BANK0123456789",
"ssn": "123456789",
"comment": "Imported through the external API",
"emergencyName": "John Doe",
"emergencyTelephone": "0611122233",
"emergencyAddress": "Second Street 2",
"emergencyCity": "Amsterdam",
"employeeRoleID": 3,
"jobRank": 4,
"photo": null,
"thirdPartyID": "employee100"
}
],
"externals": [
{
"mailAddress": "contractor@example.com",
"activated": true,
"reference": null,
"mobile": "0698765432",
"firstName": "Alex",
"lastName": "Smith",
"initials": "A",
"address": "Contractor Road 10",
"zipcode": "5678 CD",
"city": "Utrecht",
"hireCompanyReference": "existing-hire-company-reference",
"comment": "External employee",
"employeeRoleID": 5,
"jobRank": 2,
"photo": null,
"thirdPartyID": "contractor200"
}
]
}
}
Common fields (internals and externals)
| Field | Required | Format and behavior |
|---|---|---|
mailAddress |
Yes | Valid email address, normalized to lowercase. On update it must match the account belonging to reference. |
activated |
Yes | Boolean. Controls whether the account can be used. |
reference |
Yes | null to create; the existing alphanumeric TaskTime reference to update. |
mobile |
Yes | String of 10 digits starting with 06. |
firstName |
Yes | Non-empty string, max 255 characters. |
lastName |
Yes | Non-empty string, max 255 characters. |
initials |
Yes | Non-empty string, max 255 characters. |
address |
Yes | Non-empty string, max 255 characters. |
zipcode |
Yes | Non-empty string, max 255 characters. |
city |
Yes | Non-empty string, max 255 characters. |
employeeRoleID |
No | Integer ID of an employee role in the tenant, or 0 for none. Defaults to 0. |
jobRank |
No | Integer from 0 through 7. Defaults to 0. |
photo |
No | Existing TaskTime file reference or null; this endpoint does not upload image data. Defaults to null. |
comment |
No | String, max 2000 characters. Defaults to an empty string. |
thirdPartyID |
No | Your alphanumeric identifier, null or empty string. Stored on creation; not changed by updates. |
Internal employees only
| Field | Required | Format and behavior |
|---|---|---|
gender |
Yes | male or female (translated to TaskTime's internal Dutch values). |
dayOfBirth |
Yes | Date, YYYY-MM-DD. |
driversLicense |
Yes | Boolean. |
insurance, polisNumber, bankAccount, ssn |
No | Strings, default to empty string. |
emergencyName, emergencyTelephone, emergencyAddress, emergencyCity |
No | Strings, default to empty string. |
External employees only
| Field | Required | Format and behavior |
|---|---|---|
hireCompanyReference |
Yes | Reference of an existing hire company in the tenant (see List hire companies). |
An employee must stay in the same collection (internals / externals) when updated; this endpoint does not convert between internal and external.
Validation — the entire request is validated before any write happens:
reference + mailAddress combination in TaskTime.mailAddress must not already exist.hireCompanyReference and every non-zero employeeRoleID must exist in the tenant.Records are then processed one by one. A runtime failure midway does not roll back earlier records; reconcile with List employees before retrying.
Response 200 OK
{
"numberOfUpdated": 1,
"numberOfInserted": 1,
"processed": {
"inserted": [ { "mailAddress": "jane.doe@example.com", "reference": "generated-tasktime-reference", "...": "..." } ],
"updated": [ { "mailAddress": "contractor@example.com", "reference": "existing-tasktime-reference", "...": "..." } ]
}
}
processed contains the full employee objects you sent; for inserted employees reference is replaced by the generated TaskTime reference. These objects contain personal data — do not write the response to general-purpose logs.
Errors — 400 missing/invalid body structure · 401 unauthorized · 422 invalid field, identity conflict, unknown hire company or role (includes an employee key with the failing record) · 500 tenant configuration or processing failure.
Lists all employees (role professional) of the tenant, split into internal and external.
GET /api/read/employees/list/
Response 200 OK
{
"result": {
"internals": [
{
"mailAddress": "jane.doe@example.com",
"activated": true,
"reference": "abc123",
"mobile": "0612345678",
"createdOn": "2025-11-02 10:14:00",
"firstName": "Jane",
"lastName": "Doe",
"initials": "J",
"gender": "female",
"dayOfBirth": "1990-05-12",
"job": "Beveiliger",
"insurance": "Example Insurance",
"polisNumber": "POLIS100",
"bankAccount": "NL00BANK0123456789",
"driversLicense": true,
"ssn": "123456789",
"address": "Main Street 1",
"zipcode": "1234 AB",
"city": "Amsterdam",
"thirdPartyID": "employee100",
"hireCompanyReference": null,
"emergencyCity": "Amsterdam",
"comment": "",
"emergencyName": "John Doe",
"emergencyAddress": "Second Street 2",
"emergencyTelephone": "0611122233"
}
],
"externals": []
}
}
Notes:
gender is returned as male / female. activated and driversLicense are booleans.job is the name of the employee role, hireCompanyReference links an external employee to its hire company.null.result is an empty array instead of the {internals, externals} object.Errors — 400 / 401 authentication · 500 server error.
Creates and updates hire companies (uitzendbureaus) in one batch. Set reference to null to create, or pass an existing reference to update.
POST /api/sync/hireCompany/
Body
{
"hireCompanies": [
{
"reference": null,
"company": "Flexwork BV",
"kvk": "12345678",
"address": "Industrial Lane 5",
"postcode": "1234 AB",
"city": "Eindhoven",
"mobile": "0612345678",
"telephone": "0401234567",
"emailaddress": "info@flexwork.example.com",
"contactperson": "Piet Jansen",
"comment": "",
"organisation_type": "bv",
"thirdPartyID": "flexwork-01"
}
]
}
| Field | Required | Format and behavior |
|---|---|---|
reference |
Yes | null to create; existing alphanumeric reference to update. |
company |
Yes | Alphanumeric string; may contain dash, space and &. |
kvk |
Yes | String of exactly 8 digits (Dutch Chamber of Commerce number). |
address |
Yes | Non-empty alphanumeric string; may contain dash and space. |
postcode |
Yes | Non-empty alphanumeric string. |
city |
Yes | Non-empty alphanumeric string; may contain dash and space. |
mobile |
Yes | String of 10 digits starting with 06. |
telephone |
Yes | Numeric string; may contain dash, space and +. |
emailaddress |
Yes | Valid, fully lowercase email address. |
contactperson |
Yes | Alphabetic string; spaces allowed. |
comment |
Yes | String (may be empty); allowed: alphanumeric, dash, comma, semicolon, ?, ! and space. |
organisation_type |
Yes | One of: eenmanszaak, vof, cv, bv, nv, vereniging, stichting (lowercase). |
thirdPartyID |
Yes | Your non-empty alphanumeric identifier, or null. |
Response 200 OK
{
"numberOfUpdated": 0,
"numberOfInserted": 1,
"processed": {
"inserted": [ { "company": "Flexwork BV", "...": "..." } ],
"updated": []
}
}
Errors — 400 missing hireCompanies array · 401 unauthorized · 422 invalid field values or an unknown reference on update. The 422 response includes hireCompanyThatWentWrong (the failing record) and echoes the request body — treat this payload as confidential. · 500 server error.
GET /api/read/hireCompany/list/
Response 200 OK
{
"result": [
{
"address": "Industrial Lane 5",
"archived": "0",
"city": "Eindhoven",
"comment": "",
"company": "Flexwork BV",
"contactperson": "Piet Jansen",
"customerNumber": "1001",
"emailaddress": "info@flexwork.example.com",
"iban": "NL00BANK0123456789",
"kvk": "12345678",
"mobile": "0612345678",
"organisation_type": "bv",
"paymentCondition": { "days": 30 },
"postcode": "1234 AB",
"reference": "hC9a2...",
"telephone": "0401234567",
"thirdPartyID": "flexwork-01",
"vatNumber": "NL123456789B01"
}
]
}
Notes:
paymentCondition.days is a number or null when not set. customerNumber, iban and vatNumber are null when not set.reference for updates and for linking external employees (hireCompanyReference).Errors — 400 / 401 authentication · 500 server error.
Relations (customers) have locations; locations have departments. These endpoints manage that tree. All of them require the api-key header and use strict validation with precise status codes.
Field rules that apply to all six endpoints:
comment (16,000 characters).thirdPartyID is your own identifier. On create: pass your own, or omit it and a random one is generated. It can never be changed afterwards.POST /api/create/relation/
Body
| Field | Required | Description |
|---|---|---|
customer_number |
Yes | Your/debtor number for this relation |
company |
Yes | Company name — must be unique within the tenant |
kvk |
Yes | Chamber of Commerce number |
address |
Yes | Street and house number |
zipcode |
Yes | Postal code |
city |
Yes | City |
country |
Yes | Country |
emailaddress |
Yes | General email address |
invoice_email |
Yes | Email address for invoices |
mobile |
Yes | Mobile number |
contactperson |
No | Contact person name |
telephone |
No | Landline |
organisation_type |
No | Legal form |
paymentcondition |
No | Payment term |
comment |
No | Free text (max 16,000 chars) |
invoice_address, invoice_zipcode, invoice_city, invoice_department |
No | Deviating invoice address |
logo_image_reference |
No | TaskTime file reference of a logo |
thirdPartyID |
No | Your identifier (generated when omitted) |
{
"customer_number": "10025",
"company": "Harbor Services BV",
"kvk": "87654321",
"address": "Port Road 12",
"zipcode": "3011 AA",
"city": "Rotterdam",
"country": "NL",
"emailaddress": "info@harbor.example.com",
"invoice_email": "invoices@harbor.example.com",
"mobile": "0612345678",
"contactperson": "Sanne de Vries",
"organisation_type": "bv",
"paymentcondition": "30",
"thirdPartyID": "harbor-10025"
}
Response 200 OK
{
"reference": "9f2c...generated-tasktime-reference",
"thirdPartyID": "harbor-10025"
}
Errors — 400 missing/invalid fields · 401 unauthorized · 409 a relation with this company or thirdPartyID already exists · 500 save failure.
POST /api/create/location/
Body
| Field | Required | Description |
|---|---|---|
customer_reference |
Yes | reference of the parent relation |
location_number |
Yes | Your location number |
name |
Yes | Location name — must be unique within the tenant |
cost_center |
Yes | Cost center code |
address, zipcode, city |
Yes | Visit address |
contactperson, emailaddress, telephone, mobile |
Yes | Contact details of the location |
branche_reference |
No | Internal branch reference |
branche_reference_external |
No | External branch reference |
comment |
No | Free text |
thirdPartyID |
No | Your identifier (generated when omitted) |
Response 200 OK and errors are the same shape as Create a relation; additionally 404 when customer_reference does not exist.
POST /api/create/department/
Body
| Field | Required | Description |
|---|---|---|
location_reference |
Yes | reference of the parent location |
department |
Yes | Department name — must be unique within the tenant |
cost_center |
Yes | Cost center code |
branche_reference |
No | Internal branch reference |
branche_reference_external |
No | External branch reference |
thirdPartyID |
No | Your identifier (generated when omitted) |
Response 200 OK and errors are the same shape as Create a relation; additionally 404 when location_reference does not exist.
POST /api/update/relation/
POST /api/update/location/
POST /api/update/department/
Partial update: send exactly one identifier plus at least one field to change.
reference or thirdPartyID (not both).customer_reference / location_reference) and thirdPartyID.{
"thirdPartyID": "harbor-10025",
"invoice_email": "billing@harbor.example.com",
"telephone": "0101234567"
}
Response 200 OK
{
"reference": "9f2c...",
"thirdPartyID": "harbor-10025"
}
Errors — 400 no/extra identifier, no update fields, empty required values, invalid types or overlong values · 401 unauthorized · 404 no record found for the identifier · 409 the identifier matches more than one record (can only happen with duplicate thirdPartyID values) · 500 save failure.
The full relation tree: customers with their locations, and departments per location. Ordered by company name.
GET /api/read/relations/list/
Response 200 OK
{
"result": [
{
"customer": "Harbor Services BV",
"reference": "9f2c...",
"address": "Port Road 12",
"city": "Rotterdam",
"contactPerson": "Sanne de Vries",
"mailAddress": "info@harbor.example.com",
"customerNumber": "10025",
"invoiceAddress": null,
"invoiceDepartment": null,
"invoiceZipcode": null,
"invoiceCity": null,
"invoiceMailAddress": "invoices@harbor.example.com",
"kvk": "87654321",
"mobile": "0612345678",
"organisationType": "bv",
"telephone": "0101234567",
"zipcode": "3011 AA",
"country": "NL",
"thirdPartyID": "harbor-10025",
"locations": [
{
"location": "Terminal A",
"reference": "loc123...",
"locationNumber": "L-01",
"address": "Quay 1",
"zipcode": "3011 AB",
"city": "Rotterdam",
"contactPerson": "Kees Bakker",
"mailAddress": "terminal-a@harbor.example.com",
"telephone": "0101234568",
"mobile": "0612345679",
"costCenter": "CC-100",
"thirdPartyID": "harbor-loc-01",
"departments": [
{
"department": "Security",
"reference": "dep456...",
"costCenter": "CC-110",
"thirdPartyID": "harbor-dep-01"
}
]
}
]
}
]
}
Use the reference values from this endpoint as customerReference, locationReference and departmentReference when creating shifts.
Errors — 400 / 401 authentication · 500 server error.
The shift endpoints identify shifts through your reference (thirdPartyShiftReference), so you can manage TaskTime shifts without storing TaskTime IDs.
These endpoints return client-side validation failures as HTTP
500witherror: "Missing or invalid keys". Treat the combination of status code + payload as the contract.
Creates one or more shifts. Each shift is either assigned directly to a professional or created as an open shift.
POST /api/shifts/create
Body
{
"shifts": [
{
"customerReference": "fdhjdskfh7283rhjksdfh",
"locationReference": "43534534jkdshgf87",
"departmentReference": "",
"startDateTime": "2026-01-18 09:00",
"endDateTime": "2026-01-18 17:30",
"pauseTime": 0.5,
"isSleepShift": false,
"sleepStart": "00:00",
"sleepEnd": "00:00",
"jobDescription": "Night gate duty",
"job": "Beveiliger",
"thirdPartyShiftReference": "my-shift-0001"
}
],
"preferences": {
"openShift": false,
"assignToProfessionalReference": "kj3859hjkfhsdfkh23u8rhjsdk"
},
"openInvitationToEveryone": false
}
Shift object
| Field | Required | Format and behavior |
|---|---|---|
customerReference |
Yes | Relation reference (see List relations). |
locationReference |
Yes | Location reference. |
departmentReference |
No | Department reference; defaults to none. |
startDateTime |
Yes | YYYY-MM-DD HH:mm. |
endDateTime |
Yes | YYYY-MM-DD HH:mm. |
pauseTime |
No | Unpaid pause in hours (number, decimals allowed). Defaults to 0. |
isSleepShift |
No | Boolean; marks the shift as containing sleep time. Defaults to false. |
sleepStart |
Only when isSleepShift |
HH:mm, start of the sleep period. |
sleepEnd |
Only when isSleepShift |
HH:mm, end of the sleep period. |
jobDescription |
No | Free text shown on the shift. |
job |
No | Job name, for example "Beveiliger". |
thirdPartyShiftReference |
No | Your unique shift reference, used by the assign/read/delete endpoints. Defaults to external-api — always set your own. |
Preferences and options
| Field | Where | Format and behavior |
|---|---|---|
openShift |
preferences |
Boolean. When true the shift is created as an open shift. |
assignToProfessionalReference |
preferences |
Employee reference. Required when openShift is false. |
openInvitationToEveryone |
root of the body | Boolean; for open shifts, invite all professionals (they receive a push notification). Defaults to false. |
Behavior
thirdPartyShiftReference already exists are skipped, not duplicated — the call is idempotent per reference and reports skippedDuplicates.Response 200 OK
{
"error": false,
"message": "done!",
"created": 1,
"skippedDuplicates": 0
}
When every shift already existed, the response is 200 OK with created: 0 and skippedDuplicates equal to the number of skipped shifts. Invalid shift data returns 200 OK with { "error": true, "message": "Foutieve data gevonden", "info": ... } — always check the error flag.
Errors — 500 with Missing or invalid keys when shifts is empty/not an array, when customerReference/locationReference is missing, or when assignToProfessionalReference is missing while openShift is false · 400 / 401 authentication · 500 server error.
Assigns existing shifts (created earlier with your thirdPartyShiftReference) to professionals.
POST /api/shifts/assign
Body
{
"assign": [
{
"thirdPartyReference": "my-shift-0001",
"professionalReference": "kj3859hjkfhsdfkh23u8rhjsdk"
}
]
}
| Field | Required | Format and behavior |
|---|---|---|
assign |
Yes | Non-empty array. |
assign[].thirdPartyReference |
Yes | Non-empty string; your shift reference. |
assign[].professionalReference |
Yes | Employee reference (see List employees). |
Response 200 OK
{
"success": true,
"message": "Shifts assigned successfully"
}
Errors — 500 with Missing or invalid keys for an empty assign array or empty references · 400 / 401 authentication.
Returns the full shift records for your references.
POST /api/shifts/read
Body
{
"thirdPartyReferences": ["my-shift-0001", "my-shift-0002"]
}
Response 200 OK
{
"success": true,
"message": "Shifts retrieved successfully",
"data": [
{
"reference": "tt-shift-reference",
"third_party_reference": "my-shift-0001",
"user_reference": "kj3859hjkfhsdfkh23u8rhjsdk",
"customer_reference": "fdhjdskfh7283rhjksdfh",
"location_reference": "43534534jkdshgf87",
"department_reference": null,
"datetime_from": "2026-01-18 09:00",
"datetime_to": "2026-01-18 17:30",
"is_assigned": "1",
"...": "..."
}
]
}
data contains the complete shift records as stored in TaskTime (all columns); the example shows the most relevant fields. Unknown references are simply absent from data.
Errors — 500 with Missing or invalid keys for a missing/empty thirdPartyReferences array or empty values · 400 / 401 authentication.
Permanently deletes the shifts with the given references.
POST /api/shifts/delete
Body
{
"thirdPartyReferences": ["my-shift-0001"]
}
Response 200 OK
{
"success": true,
"message": "Shifts deleted successfully"
}
Deletion is immediate and not reversible. References that do not exist are ignored.
Errors — 500 with Missing or invalid keys for invalid input · 400 / 401 authentication.
Lists all projects of the tenant, including slots and sub-projects.
GET /api/read/projects/list
Response 200 OK
The response contains the same data in two shapes:
relations — projects grouped per relation → location (sub-projects inside their location).projects — the flat list of all projects (sub-projects nested inside their parent).{
"result": {
"relations": [
{
"relation_reference": "9f2c...",
"locations": [
{
"location_reference": "loc123...",
"projects": [ { "reference": "prj789...", "...": "see project model below" } ]
}
]
}
],
"projects": [
{
"reference": "prj789...",
"created_on": "2025-12-01 09:00:00",
"project_name": "Winter security Terminal A",
"project_description": "...",
"project_work": "...",
"relation_reference": "9f2c...",
"location_reference": "loc123...",
"department_reference": "dep456...",
"period_from": "2026-01-01",
"period_to": "2026-03-31",
"project_status": "active",
"cost_center": "CC-100",
"weekly_hours_min": 24,
"weekly_hours_max": 40,
"contact_person_name": "Sanne de Vries",
"contact_person_role": "Planner",
"contact_person_telephone": "0101234567",
"contact_person_mail": "sanne@harbor.example.com",
"signing_person_name": "...",
"signing_person_role": "...",
"signing_person_telephone": "...",
"signing_person_mail": "...",
"approver_person_name": "...",
"approver_person_role": "...",
"approver_person_telephone": "...",
"approver_person_mail": "...",
"invoice_mail": "invoices@harbor.example.com",
"rate_per_hour": 32.5,
"ort_branche_reference": "...",
"btw_type": "high-exclusive",
"btw_percentage": 21,
"travel_cost_km": 0.21,
"travel_cost_money": 0,
"travel_cost_type": "per_km",
"slots": [
{
"reference": "slot001...",
"project_reference": "prj789...",
"employee_reference": null,
"slot_number": 1,
"is_assigned": false,
"btw_percentage": 21,
"btw_type": "high-exclusive",
"job_name": "Beveiliger",
"ort_branche_reference": "...",
"position": "Security officer",
"position_rank": 2,
"rate_per_hour": 32.5,
"self_planning": false,
"travel_cost_km": 0.21,
"travel_cost_money": 0,
"travel_cost_type": "per_km",
"work_hours_hours_from": 20,
"work_hours_hours_to": 32,
"work_hours_type": "weekly"
}
],
"subprojects": []
}
]
}
}
Errors — 400 / 401 authentication · 500 server error.
POST /api/update/projects/assignToSlot
Body
{
"projectReference": "prj789...",
"slotReference": "slot001...",
"employeeReference": "kj3859hjkfhsdfkh23u8rhjsdk"
}
All three keys are required. Validations: the professional must exist and be activated, and the slot must exist within the project and still be available.
Response 200 OK
{
"result": {
"success": true,
"message": ""
}
}
Errors — 500 with Missing keys when a key is absent · 500 with Could not assign employee to slot when the employee is unknown/inactive, the slot is not found, or the slot is already assigned (message contains the reason) · 400 / 401 authentication.
Returns all processed invoices and collection specifications (verzamelfacturen) with an invoice date inside the period, for both regular invoicing and reversed billing (factoring/self-billing).
POST /api/invoices/byPeriod
Body
{
"from": "2026-07-01",
"to": "2026-07-31"
}
Both dates are required, format YYYY-MM-DD. The period is inclusive and matched on the (manual) invoice date.
Response 200 OK
{
"invoices": {
"regular": [
{
"invoiceNumber": "2026-1042",
"paymentStatus": "open",
"paymentMethod": {
"scheme": "UNCL4461",
"code": "30",
"description": "Credit Transfer",
"label": "Bankoverschrijving"
},
"amount": {
"open": { "includedTax": 1210.00, "excludedTax": 1000.00, "tax": 210.00 },
"original": { "includedTax": 1210.00, "excludedTax": 1000.00, "tax": 210.00 },
"credited": { "includedTax": 0, "excludedTax": 0, "tax": 0 },
"paid": { "includedTax": 0 },
"currency": "EUR"
},
"pdf": {
"endpointUrl": "https://api.tasktime.eu/pdfmachine/previewInvoice",
"method": "POST",
"body": {
"downloadUrl": "https://.../invoice.pdf",
"runReference": "run-ref..."
}
},
"dates": {
"dateOfInvoice": "2026-07-15 10:04:00",
"expireDate": "2026-08-14"
},
"taxSettings": {
"type": "high-exclusive",
"label": "Hoog BTW-tarief (exclusief)",
"percentage": "21",
"included": false
},
"debtor": {
"company": "Harbor Services BV",
"reference": "9f2c...",
"address": {
"streetAndNumber": "Port Road 12",
"postalCode": "3011 AA",
"city": "Rotterdam",
"country": "NL"
}
},
"creditor": {
"company": "Security Plus",
"reference": "org-ref...",
"address": { "...": "..." },
"bankDetails": {
"iban": "NL00BANK0123456789",
"vatNumber": "NL123456789B01",
"bankAccountName": "Security Plus BV",
"btwNumber": "NL123456789B01"
}
},
"creditInvoices": [
{
"invoiceNumber": "2026-1055",
"creditAmount": { "includedTax": -121.00, "excludedTax": -100.00, "tax": -21.00, "currency": "EUR" },
"pdf": { "endpointUrl": "https://api.tasktime.eu/pdfmachine/previewInvoice", "method": "POST", "body": { "downloadUrl": null, "runReference": "run-ref..." } },
"dateOfInvoice": "2026-07-20",
"dateOfExpire": "2026-08-19"
}
]
}
],
"reversed": []
}
}
Reading guide:
invoiceNumber are invoices; collection specifications carry specificationNumber instead and additionally contain commissionInvoices (related intermediation/factoring commission invoices) and creditSpecifications instead of creditInvoices.amount.open is the current open amount, amount.original the amount at invoice date, amount.credited the total credited since, amount.paid.includedTax the partially paid amount. All amounts are numbers with two decimals; currency is EUR.pdf describes how to fetch the PDF: POST the given body to endpointUrl.taxSettings.type is one of none, high-inclusive, high-exclusive, low-inclusive, low-exclusive, nul, free, relocated; label is its Dutch description; included tells whether the amounts include VAT.debtor / creditor are resolved against customers, the tenant organisation and hire companies; bankDetails is present for organisations and hire companies. A party that no longer exists resolves to null.Errors — 500 with Missing or invalid keys when from/to are missing or not YYYY-MM-DD · 400 / 401 authentication · 500 server error.
Returns the tenant organisation details as used on invoices (creditor data).
GET /api/read/invoice/organisation/details/
Response 200 OK
{
"result": {
"organisation": "Security Plus",
"address": "Office Park 1",
"postal_code": "5611 AA",
"city": "Eindhoven",
"mailaddress": "finance@securityplus.example.com",
"website_url": "https://...",
"kvk_number": "12345678",
"btw_number": "NL123456789B01",
"iban_account": "NL00BANK0123456789",
"g_account": "",
"logo_url": "https://...",
"vat_number": "NL123456789B01",
"bank_account_name": "Security Plus BV",
"term_of_payment_days": 30,
"...": "..."
}
}
When no settings exist yet, the fields above are returned with empty strings / 0.
Errors — 400 / 401 authentication · 500 server error.
Returns the payroll-relevant hours of one employee over a period, split by ORT (on-call/irregular hours surcharge) percentage, per day and per cost center.
POST /api/read/payment/
Body
{
"employeeReference": "kj3859hjkfhsdfkh23u8rhjsdk",
"from": "2026-07-01",
"to": "2026-07-31"
}
| Field | Required | Format and behavior |
|---|---|---|
employeeReference |
Yes | Existing employee (user) reference. |
from |
Yes | YYYY-MM-DD. |
to |
Yes | YYYY-MM-DD; maximum range is 31 days. |
Response 200 OK
{
"groupedByCostCenter": [
{
"costCenter": "CC-100",
"totalHours": 152.5,
"ortTotals": [
{ "percentage": 100, "duration": 140.0 },
{ "percentage": 140, "duration": 12.5 }
],
"ortDays": [
{
"date": "2026-07-06",
"totalHours": 8,
"ort": [
{ "percentage": 100, "duration": 8 }
]
}
]
}
],
"withoutCostCenter": {
"ortDays": [
{ "date": "2026-07-06", "totalHours": 8, "ort": [ { "percentage": 100, "duration": 8 } ] }
],
"ortTotals": [ { "percentage": 100, "duration": 140.0 } ],
"totalHours": 152.5
}
}
Notes:
ortDays, also days without hours.duration values are hours; percentage is the ORT percentage (100 = regular hours).groupedByCostCenter splits the same data per department/location cost center; withoutCostCenter is the overall view.Errors — 422 missing/unknown employeeReference, invalid dates, or a range over 31 days (message explains which rule failed) · 400 / 401 authentication · 500 server error.
Returns all assigned shifts in a period, grouped per relation → location → department, with calculated totals per group. This is the dataset for invoice checking and hour declarations.
POST /api/read/totals/
Body
{
"from": "2026-07-01",
"to": "2026-07-31"
}
Both dates are required, format YYYY-MM-DD; maximum range is 31 days.
Response 200 OK (structure)
{
"customers": [
{
"customerReference": "9f2c...",
"shifts": [ { "...": "shift object, see below" } ],
"totals": {
"billableHours": 320.5,
"travelKM": 412.0,
"numberOfShifts": 40,
"ortPercentages": [
{ "ortPercentage": 100, "billableHours": 300.0 },
{ "ortPercentage": 140, "billableHours": 20.5 }
]
},
"locations": [
{
"locationReference": "loc123...",
"shifts": [ "..." ],
"totals": { "...": "same totals model" },
"departments": [
{
"departmentReference": "dep456...",
"shifts": [ "..." ],
"totals": { "...": "same totals model" }
}
]
}
]
}
]
}
The same shift objects appear at every applicable level (customer, location and — when set — department), and each level has its own totals.
Shift object
| Field | Description |
|---|---|
id |
TaskTime shift reference |
dataString, dataStringV2 |
SHA-256 fingerprints of the shift data, for change detection on your side |
date |
Shift date, DD-MM-YYYY |
startDateTime, endDateTime |
YYYY-MM-DD HH:mm |
shiftJob |
Job name |
pauseTimeInHours |
Unpaid pause |
sleepTimeInHours |
Sleep time within the shift |
employeeReference |
Employee who worked the shift |
employeeInternal |
1 internal employee, 0 external |
travelDistanceKM |
Declared travel distance |
travelDistanceCapKM |
The kilometer cap in effect (location cap, otherwise customer cap; null = uncapped) |
travelDistanceWithCapIncludedKM |
Billable kilometers after applying the cap |
travelDistanceCapOverridden |
Boolean — true when the cap is intentionally overridden and the full distance is billed |
additionalTravelDistanceKM |
Extra billable kilometers on top |
shiftHours |
Total shift hours |
approved |
Boolean — whether the hours are approved by the relation for the covering week |
ortBlocks |
Time blocks the shift is built from (see below) |
ORT block
| Field | Description |
|---|---|
blockType |
Type of block (for example regular or sleeptime) |
startDateTime, endDateTime |
YYYY-MM-DD HH:mm |
durationInHours |
Full duration of the block |
ortPercentage |
Applied ORT percentage (100 = regular) |
billingDurationInHours |
Billable hours of the block (for sleep time: the payable hours) |
unpaidByPauseTimeInHours |
Unpaid part caused by pause, or null |
Errors — 422 invalid dates or a range over 31 days · 400 / 401 authentication · 500 server error.
| Code | Meaning |
|---|---|
200 |
Success. On shift operations, still check the error / success flags in the payload. |
400 |
Missing or malformed api-key header, malformed JSON body, or invalid body structure (relations, sync endpoints). |
401 |
Unknown or unauthorized API key. |
404 |
Parent/reference not found (relations endpoints). |
409 |
Duplicate record or ambiguous identifier (relations endpoints). |
422 |
Field-level validation failure (sync, payment and totals endpoints). |
429 |
Too many concurrent requests — wait for running requests to finish, then retry. Currently not enforced. |
500 |
Server error; on shifts/invoices/projects also used for request validation failures (Missing or invalid keys). |
Questions or key requests: support@tasktime.nl