REST DokumentationChangelog

Changelog

Die Spezifikation der REST-API wird aus dem Quellcode erzeugt und mit jedem ZEP-Release veröffentlicht. Seit der Umstellung auf die generierte Spezifikation beschreibt die Versionsnummer den API-Vertrag (1.x.y), nicht mehr das Produkt-Release: eine brechende Änderung erhöht die Hauptversion und landet in einem neuen /api/v2, additive Änderungen bleiben in v1. Releases nach der Umstellung schreibt die Release-Pipeline aus dem Diff der Spezifikation (Änderungstexte auf Englisch); sie erscheinen nur, wenn sich die API geändert hat. Das Release der Umstellung und alles davor ist von Hand geschrieben.

v8.0.90.2 · OpenAPI 1.2.0 · 05.11.2026

PUT/PATCH /employees/{employee}/regular-working-times/{id} keeps the holiday calendar

An update without holiday_calendar_id reset the schedule’s holiday calendar to the default calendar. It now stays as it is; only an explicit holiday_calendar_id changes it. POST without it still sets the default calendar.

v8.0.84 · OpenAPI 1.2.0 · 02.11.2026

limit is honoured: GET /projects/{id}/tasks

The task list ignored limit and always returned 15 tasks per page; perPage accepted only 5, 10 or 15. limit now sets the page size, 1 to 200, and a value outside that range answers 422, as on every other list. perPage is ignored on this endpoint, the same as elsewhere (the published specification still lists 5, 10, 15 for it), and limit is declared in the published specification.

v8.0.75 · OpenAPI 1.0.0 → 1.1.0 · 30.10.2026

Billing lock covers stored bookings: PUT, PATCH and DELETE /attendances/{id}

A booking inside an invoiced period (approved or billed invoice item) or attached to an invoice item can no longer be changed or deleted: the request answers 422 Billing is blocked. and nothing is saved. Before, only the new state of a PUT was checked, so a locked booking could be moved out, made non-billable or deleted. The lock on these three requests can be switched off per tenant; switched off, they behave as before this change.

Nested lists honour limit: GET /customers/{customer}/price-tables, /customers/{customer}/contacts, /departments/{department}/children, /departments/{department}/employees, /employees/{employee}/absences, /employees/{employee}/meals, /employees/{employee}/transponders, /offers/{offer}/items, /projects/{project}/activities, /projects/{project}/locations, /receipts/{receipt}/amounts, /tickets/{ticket}/subtasks, /devices

These lists ignored limit and always answered 15 entries per page. They now take limit (1 to 200, 422 outside it, default 15) and page, in a stable order, and the page links keep limit. Besides limit and page they accept no parameters, except GET /departments, which keeps its start_date and end_date filters and its orderBy and order sorting and now honours limit as well.

Pagination links keep the query: GET /plannings

links.first, prev, next and last of GET /plannings dropped the query string, so following next returned unfiltered data, 15 per page, instead of the page of the request’s modified_after, limit, include_defaults and other filters. They now carry every parameter of the request, with and without include_defaults. The other paginated lists (for example GET /customers/{customer_number}/contacts) pass the query string through in their links as well, which changes nothing in what they return; the nested ones also take limit.

Billing lock for bookings: POST /attendances, PUT /attendances/{id}

A billable booking into a period that an approved or billed invoice item of the project covers is now rejected with 422 and the message “Billing is blocked.”, as in the web UI. Moving an existing booking into such a period is rejected the same way, and a booking already attached to an invoice item stays locked. Needs the invoicing module; the Jira worklog import skips such bookings with the same reason.

Alle Einzeländerungen (2)
  • NEU GET /customers/{customer_number}/contacts, GET /customers/{customer_number}/price-tables, GET /departments/{id}/children, GET /departments/{id}/employees, GET /devices, GET /employees/{username}/absences, GET /employees/{username}/meals, GET /employees/{username}/transponders, GET /offers/{id}/items, GET /projects/{id}/activities, GET /projects/{id}/locations, GET /receipts/{id}/amounts, GET /tickets/{id}/subtasks: added the new optional query request parameter limit
  • NEU GET /customers/{customer_number}/contacts, GET /customers/{customer_number}/price-tables, GET /departments/{id}/children, GET /departments/{id}/employees, GET /devices, GET /employees/{username}/absences, GET /employees/{username}/meals, GET /employees/{username}/transponders, GET /offers/{id}/items, GET /projects/{id}/activities, GET /projects/{id}/locations, GET /receipts/{id}/amounts, GET /tickets/{id}/subtasks: added the non-success response with the status 422

v8.0.59 · OpenAPI 1.0.0 · 28.10.2026

Rate limit: all customer operations

The specification now documents the limit the API has enforced: 1000 requests per 5 minutes per tenant, plus at most 25 concurrent requests per tenant. Every operation lists the 429 answer ({"message": "Too Many Attempts."} with Retry-After, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining), and every success response lists X-RateLimit-Limit and X-RateLimit-Remaining. Documentation only, no behaviour change.

Tasks: all_project_employees on GET /projects/{id}/tasks

Every task now reports all_project_employees: true when all project employees may book on it, false when only the employees listed under GET /projects/{id}/tasks/{task_id}/employees may. The employee list of a task with all_project_employees: true is empty on purpose.

Employees: cost_center, note, overtime_ads and project_number

GET/POST/PUT /employees and GET /departments/{id}/employees now return cost_center (Kostenstelle, separate from cost_bearer), note and overtime_ads (boolean, null when never set). Project assignments on /employees/{employee}/projects and /projects/{project}/employees carry project_number. Licence: as before.

Employees: include for employment periods, regular working times and internal rates

GET /employees and GET /employees/{employee} accept include=employment_periods,regular_working_times,internal_rates (any subset, comma-separated) and embed those lists in each employee under the same key, in the shape of the per-employee endpoints; the lists are complete, not paged, and empty ones are []. An unknown value answers 422; on a Clock licence internal_rates is unknown, as the internal-rates endpoint is not offered there either. With include=internal_rates, modified_after also finds an employee whose internal rate changed, and modified_before leaves out one whose internal rate changed after the bound; a deleted internal rate leaves no timestamp and is not detected. Employment period and working time changes already move the employee’s modified. Without include nothing changes. Licence: as before.

Project assignments: GET /project-employees

Lists the project assignments of all projects in one paginated call, ordered by id. Filter by project_id and employee_id (a single value or a list), project_status, project_start_date and project_end_date. Not available on ZEP Clock.

Project assignments of a project: GET /projects/{project}/employees

project_status, project_start_date and project_end_date were accepted but ignored; they now narrow the list like they do on GET /employees/{employee}/projects.

Invoice filters and positions: GET /invoices

New query parameters modified_after (exclusive) and modified_before (inclusive) restrict the list to invoices changed in a time window; the modified value of a response works as the next modified_after. start_date and end_date (YYYY-MM-DD, both inclusive, either one alone is allowed) filter by the invoice date. include=items embeds each invoice’s positions as items, in the form of GET /invoices/{invoice}/items, so no call per invoice is needed; without include the key is absent. An unknown include value answers 422. A position change does not necessarily move the invoice’s modified.

A client generated from the specification compiles: GET /plannings, GET /employees, GET /folders/{id}/documents, GET /folders/{id}/documents/{document_id}, GET /projects/{id}/employees, GET /employees/{id}/projects

The specification described planning_details.type and unit as always null and listed an empty value for salutation.name; both now match the answers (type is percentage, hours, time_range, days or null, unit is %, hours, time, days or null; salutation.name is a plain string). Document and ProjectEmployee are documented as the object they return, without the empty-array alternative. A document in a folder without a file system answers file_contents: null with filename and type, no longer an empty array, and the planning times from, to, from_time and to_time are documented as HH:MM:SS strings, not date-times. The values themselves do not change.

Task employees: no stored assignments while the task is open to all project employees

The list is now empty while the task has all_project_employees: true, even if assignments from an earlier explicit setup are still stored, and GET /projects/{id}/tasks/{task_id}/employees/{id} returns 404 for such an assignment. Booking already ignored them.

Employee sub-lists honour limit and page: GET /employees/{employee}/employment-periods, /regular-working-times, /internal-rates

These three lists ignored limit and always answered 15 entries per page. They now page like every other list: limit 1 to 200 (422 outside it), default 15, plus page. A client that sent limit and relied on it being ignored gets the requested page size.

Absence creation answers with the real outcome: POST /absences

A created absence now answers 201 instead of 200. A request ZEP rejects on business grounds (for example an absence before the introduction date of the absence module) answers 422 with ZEP’s code, message and the message again under errors.absence, and any other failure on the ZEP side answers 502; both used to come back as 200. Only ZEP code 104 counts as a rejection (ZEP also answers a storage error with it); every other ZEP error code answers 502. A half-day (type 1) or hourly (type 2) absence is now stored with that type; it used to be stored as a full day. timezone is optional for every absence type and defaults to the server’s timezone.

Absences return created and modified: GET /absences, GET /absences/{id}

created and modified were always null on absences, on the embedded absenceReason and on GET /absence-reasons and GET /articles; they now carry the stored timestamps, in UTC. Legacy rows with a zero-date (0000-00-00 00:00:00) still answer null.

The specification matches the responses: types, nullable fields, date formats, cursor

Documentation only, no response changes. ProjectStatus.id is a string (the short name, e.g. Aktiv), Department.id is an integer, Project.keywords is a list of strings. CustomerContact.primary, Invoice.correction_date, Invoice.email_sent_at, Invoice.email_recipient, Invoice.note, Price.price and Project.project_status_id can be null. start_date of a price table, end_date of an attendance and from/to of a project task employee carry format: date. Invoice.correction_date is documented as local time Y-m-d H:i:s without a zone. On GET /attendances, modified_after is an inclusive cursor paired with id_after (default 0, effective only together with modified_after). oasdiff rates the type and nullability corrections as breaking; the release changelog marks them as fixes, because the frozen contract already says the same. The narrowed formats and Department.id, Project.keywords stay as oasdiff rates them.

Alle Einzeländerungen (144)
  • KORREKTUR GET /customers, GET /projects: the response property data/items/priceTables/items/prices/items/price became nullable for the status 200
  • KORREKTUR GET /customers, GET /projects: the data/items/priceTables/items/start_date response’s property format changed from date-time to date for status 200
  • KORREKTUR POST /customers: the response property data/allOf[subschema #1: CustomerResource]/priceTables/items/prices/items/price became nullable for the status 201
  • KORREKTUR POST /customers: the data/allOf[subschema #1: CustomerResource]/priceTables/items/start_date response’s property format changed from date-time to date for status 201
  • KORREKTUR GET /customers/{customer_number}, GET /projects/{id}: the response property data/priceTables/items/prices/items/price became nullable for the status 200
  • KORREKTUR GET /customers/{customer_number}, GET /projects/{id}: the data/priceTables/items/start_date response’s property format changed from date-time to date for status 200
  • KORREKTUR PATCH /customers/{customer_number}, PUT /customers/{customer_number}: the response property data/allOf[subschema #1: CustomerResource]/priceTables/items/prices/items/price became nullable for the status 200
  • KORREKTUR PATCH /customers/{customer_number}, PUT /customers/{customer_number}: the data/allOf[subschema #1: CustomerResource]/priceTables/items/start_date response’s property format changed from date-time to date for status 200
  • KORREKTUR GET /customers/{customer_number}/contacts: the response property data/items/primary became nullable for the status 200
  • KORREKTUR POST /customers/{customer_number}/contacts: the response property data/allOf[subschema #1: CustomerContactResource]/primary became nullable for the status 201
  • KORREKTUR GET /customers/{customer_number}/contacts/{id}: the response property data/primary became nullable for the status 200
  • KORREKTUR PATCH /customers/{customer_number}/contacts/{id}, PUT /customers/{customer_number}/contacts/{id}: the response property data/allOf[subschema #1: CustomerContactResource]/primary became nullable for the status 200
  • KORREKTUR GET /customers/{customer_number}/price-tables, GET /projects/{id}/price-tables: the response property data/items/prices/items/price became nullable for the status 200
  • KORREKTUR GET /customers/{customer_number}/price-tables, GET /projects/{id}/price-tables: the data/items/start_date response’s property format changed from date-time to date for status 200
  • KORREKTUR GET /customers/{customer_number}/price-tables/{id}, GET /projects/{id}/price-tables/{price_table_id}: the response property data/prices/items/price became nullable for the status 200
  • KORREKTUR GET /customers/{customer_number}/price-tables/{id}, GET /projects/{id}/price-tables/{price_table_id}: the data/start_date response’s property format changed from date-time to date for status 200
  • KORREKTUR GET /invoices: the response property data/items/correction_date became nullable for the status 200
  • KORREKTUR GET /invoices: the response property data/items/email_recipient became nullable for the status 200
  • KORREKTUR GET /invoices: the response property data/items/email_sent_at became nullable for the status 200
  • KORREKTUR GET /invoices: the response property data/items/note became nullable for the status 200
  • KORREKTUR GET /invoices/{invoice_number}: the response property data/correction_date became nullable for the status 200
  • KORREKTUR GET /invoices/{invoice_number}: the response property data/email_recipient became nullable for the status 200
  • KORREKTUR GET /invoices/{invoice_number}: the response property data/email_sent_at became nullable for the status 200
  • KORREKTUR GET /invoices/{invoice_number}: the response property data/note became nullable for the status 200
  • KORREKTUR GET /plannings: the data/items/from response’s property format changed from date-time to none for status 200
  • KORREKTUR GET /plannings: the data/items/to response’s property format changed from date-time to none for status 200
  • KORREKTUR GET /projects: the response property data/items/project_status_id became nullable for the status 200
  • KORREKTUR GET /projects: the data/items/status/allOf[subschema #1: ProjectStatusResource]/id response’s property type changed from integer to string for status 200
  • KORREKTUR POST /projects: the response property data/allOf[subschema #1: ProjectResource]/priceTables/items/prices/items/price became nullable for the status 201
  • KORREKTUR POST /projects: the response property data/allOf[subschema #1: ProjectResource]/project_status_id became nullable for the status 201
  • KORREKTUR POST /projects: the data/allOf[subschema #1: ProjectResource]/priceTables/items/start_date response’s property format changed from date-time to date for status 201
  • KORREKTUR POST /projects: the data/allOf[subschema #1: ProjectResource]/status/allOf[subschema #1: ProjectStatusResource]/id response’s property type changed from integer to string for status 201
  • KORREKTUR GET /projects/{id}: the response property data/project_status_id became nullable for the status 200
  • KORREKTUR GET /projects/{id}: the data/status/allOf[subschema #1: ProjectStatusResource]/id response’s property type changed from integer to string for status 200
  • KORREKTUR PATCH /projects/{id}, PUT /projects/{id}: the response property data/allOf[subschema #1: ProjectResource]/priceTables/items/prices/items/price became nullable for the status 200
  • KORREKTUR PATCH /projects/{id}, PUT /projects/{id}: the response property data/allOf[subschema #1: ProjectResource]/project_status_id became nullable for the status 200
  • KORREKTUR PATCH /projects/{id}, PUT /projects/{id}: the data/allOf[subschema #1: ProjectResource]/priceTables/items/start_date response’s property format changed from date-time to date for status 200
  • KORREKTUR PATCH /projects/{id}, PUT /projects/{id}: the data/allOf[subschema #1: ProjectResource]/status/allOf[subschema #1: ProjectStatusResource]/id response’s property type changed from integer to string for status 200
  • INFO removed the schema Json
  • INFO a breaking change was detected but the version is still 1.0.0
  • NEU GET /absence-reasons, GET /absence-reasons/{name}, GET /absences, GET /absences/{id}, GET /activities, GET /activities/{activity}, GET /articles, GET /articles/{id}, GET /attendances, DELETE /attendances/{id}, GET /attendances/{id}, PATCH /attendances/{id}, PUT /attendances/{id}, GET /categories, GET /categories/{name}, GET /customers, DELETE /customers/{customer_number}, GET /customers/{customer_number}, PATCH /customers/{customer_number}, PUT /customers/{customer_number}, GET /customers/{customer_number}/contacts, DELETE /customers/{customer_number}/contacts/{id}, GET /customers/{customer_number}/contacts/{id}, PATCH /customers/{customer_number}/contacts/{id}, PUT /customers/{customer_number}/contacts/{id}, GET /customers/{customer_number}/price-tables, GET /customers/{customer_number}/price-tables/{id}, GET /departments, GET /departments/{id}, GET /departments/{id}/children, GET /departments/{id}/employees, GET /devices, GET /devices/{id}, GET /dynamic-attributes, GET /dynamic-attributes/{id}, GET /employees, GET /employees/{username}, PATCH /employees/{username}, PUT /employees/{username}, GET /employees/{username}/absences, GET /employees/{username}/employment-periods, GET /employees/{username}/employment-periods/{id}, PATCH /employees/{username}/employment-periods/{id}, PUT /employees/{username}/employment-periods/{id}, GET /employees/{username}/internal-rates, GET /employees/{username}/internal-rates/{id}, GET /employees/{username}/meals, GET /employees/{username}/meals/{id}, GET /employees/{username}/projects, GET /employees/{username}/regular-working-times, GET /employees/{username}/regular-working-times/{id}, PATCH /employees/{username}/regular-working-times/{id}, PUT /employees/{username}/regular-working-times/{id}, GET /employees/{username}/transponders, GET /folders, GET /folders/{id}, GET /folders/{id}/documents, GET /folders/{id}/documents/{document_id}, GET /invoice-items, GET /invoice-items/{id}, GET /invoices, GET /invoices/{invoice_number}, GET /invoices/{invoice_number}/attachments, GET /invoices/{invoice_number}/items, GET /location-lists, GET /location-lists/{id}, GET /location-lists/{id}/locations, GET /locations, GET /locations/{name}, GET /offers, GET /offers/{id}, GET /offers/{id}/items, GET /offers/{id}/items/{item_id}, GET /planning, GET /plannings, GET /price-groups, GET /price-groups/{id}, GET /projects, DELETE /projects/{id}, GET /projects/{id}, PATCH /projects/{id}, PUT /projects/{id}, GET /projects/{id}/activities, GET /projects/{id}/employees, GET /projects/{id}/invoice-items, GET /projects/{id}/locations, GET /projects/{id}/price-tables, GET /projects/{id}/price-tables/{price_table_id}, GET /projects/{id}/tasks, DELETE /projects/{id}/tasks/{task_id}, GET /projects/{id}/tasks/{task_id}, PATCH /projects/{id}/tasks/{task_id}, PUT /projects/{id}/tasks/{task_id}, GET /projects/{id}/tasks/{task_id}/employees, GET /projects/{id}/tasks/{task_id}/employees/{project_task_employee_id}, GET /receipts, POST /receipts, GET /receipts-amounts, DELETE /receipts/{id}, GET /receipts/{id}, PATCH /receipts/{id}, PUT /receipts/{id}, GET /receipts/{id}/amounts, GET /receipts/{id}/amounts/{amount_id}, DELETE /receipts/{id}/attachments, GET /receipts/{id}/attachments, PUT /receipts/{id}/attachments, GET /resource-plannings, GET /tickets, POST /tickets, DELETE /tickets/{id}, GET /tickets/{id}, PATCH /tickets/{id}, PUT /tickets/{id}, POST /tickets/{id}/attachments, GET /tickets/{id}/subtasks, POST /tickets/{id}/subtasks, DELETE /tickets/{id}/subtasks/{subtask_id}, GET /tickets/{id}/subtasks/{subtask_id}, PATCH /tickets/{id}/subtasks/{subtask_id}, PUT /tickets/{id}/subtasks/{subtask_id}, GET /vehicles, GET /workhour-balances, GET /workhour-balances/{id}: the response header x-ratelimit-limit was added for the status 200
  • NEU GET /absence-reasons, GET /absence-reasons/{name}, GET /absences, GET /absences/{id}, GET /activities, GET /activities/{activity}, GET /articles, GET /articles/{id}, GET /attendances, DELETE /attendances/{id}, GET /attendances/{id}, PATCH /attendances/{id}, PUT /attendances/{id}, GET /categories, GET /categories/{name}, GET /customers, DELETE /customers/{customer_number}, GET /customers/{customer_number}, PATCH /customers/{customer_number}, PUT /customers/{customer_number}, GET /customers/{customer_number}/contacts, DELETE /customers/{customer_number}/contacts/{id}, GET /customers/{customer_number}/contacts/{id}, PATCH /customers/{customer_number}/contacts/{id}, PUT /customers/{customer_number}/contacts/{id}, GET /customers/{customer_number}/price-tables, GET /customers/{customer_number}/price-tables/{id}, GET /departments, GET /departments/{id}, GET /departments/{id}/children, GET /departments/{id}/employees, GET /devices, GET /devices/{id}, GET /dynamic-attributes, GET /dynamic-attributes/{id}, GET /employees, GET /employees/{username}, PATCH /employees/{username}, PUT /employees/{username}, GET /employees/{username}/absences, GET /employees/{username}/employment-periods, GET /employees/{username}/employment-periods/{id}, PATCH /employees/{username}/employment-periods/{id}, PUT /employees/{username}/employment-periods/{id}, GET /employees/{username}/internal-rates, GET /employees/{username}/internal-rates/{id}, GET /employees/{username}/meals, GET /employees/{username}/meals/{id}, GET /employees/{username}/projects, GET /employees/{username}/regular-working-times, GET /employees/{username}/regular-working-times/{id}, PATCH /employees/{username}/regular-working-times/{id}, PUT /employees/{username}/regular-working-times/{id}, GET /employees/{username}/transponders, GET /folders, GET /folders/{id}, GET /folders/{id}/documents, GET /folders/{id}/documents/{document_id}, GET /invoice-items, GET /invoice-items/{id}, GET /invoices, GET /invoices/{invoice_number}, GET /invoices/{invoice_number}/attachments, GET /invoices/{invoice_number}/items, GET /location-lists, GET /location-lists/{id}, GET /location-lists/{id}/locations, GET /locations, GET /locations/{name}, GET /offers, GET /offers/{id}, GET /offers/{id}/items, GET /offers/{id}/items/{item_id}, GET /planning, GET /plannings, GET /price-groups, GET /price-groups/{id}, GET /projects, DELETE /projects/{id}, GET /projects/{id}, PATCH /projects/{id}, PUT /projects/{id}, GET /projects/{id}/activities, GET /projects/{id}/employees, GET /projects/{id}/invoice-items, GET /projects/{id}/locations, GET /projects/{id}/price-tables, GET /projects/{id}/price-tables/{price_table_id}, GET /projects/{id}/tasks, DELETE /projects/{id}/tasks/{task_id}, GET /projects/{id}/tasks/{task_id}, PATCH /projects/{id}/tasks/{task_id}, PUT /projects/{id}/tasks/{task_id}, GET /projects/{id}/tasks/{task_id}/employees, GET /projects/{id}/tasks/{task_id}/employees/{project_task_employee_id}, GET /receipts, POST /receipts, GET /receipts-amounts, DELETE /receipts/{id}, GET /receipts/{id}, PATCH /receipts/{id}, PUT /receipts/{id}, GET /receipts/{id}/amounts, GET /receipts/{id}/amounts/{amount_id}, DELETE /receipts/{id}/attachments, GET /receipts/{id}/attachments, PUT /receipts/{id}/attachments, GET /resource-plannings, GET /tickets, POST /tickets, DELETE /tickets/{id}, GET /tickets/{id}, PATCH /tickets/{id}, PUT /tickets/{id}, POST /tickets/{id}/attachments, GET /tickets/{id}/subtasks, POST /tickets/{id}/subtasks, DELETE /tickets/{id}/subtasks/{subtask_id}, GET /tickets/{id}/subtasks/{subtask_id}, PATCH /tickets/{id}/subtasks/{subtask_id}, PUT /tickets/{id}/subtasks/{subtask_id}, GET /vehicles, GET /workhour-balances, GET /workhour-balances/{id}: the response header x-ratelimit-remaining was added for the status 200
  • NEU GET /absence-reasons, GET /absence-reasons/{name}, GET /absences, POST /absences, GET /absences/{id}, GET /activities, GET /activities/{activity}, GET /articles, GET /articles/{id}, GET /attendances, POST /attendances, DELETE /attendances/{id}, GET /attendances/{id}, PATCH /attendances/{id}, PUT /attendances/{id}, GET /categories, GET /categories/{name}, GET /customers, POST /customers, DELETE /customers/{customer_number}, GET /customers/{customer_number}, PATCH /customers/{customer_number}, PUT /customers/{customer_number}, GET /customers/{customer_number}/contacts, POST /customers/{customer_number}/contacts, DELETE /customers/{customer_number}/contacts/{id}, GET /customers/{customer_number}/contacts/{id}, PATCH /customers/{customer_number}/contacts/{id}, PUT /customers/{customer_number}/contacts/{id}, GET /customers/{customer_number}/price-tables, GET /customers/{customer_number}/price-tables/{id}, GET /departments, GET /departments/{id}, GET /departments/{id}/children, GET /departments/{id}/employees, GET /devices, GET /devices/{id}, GET /dynamic-attributes, GET /dynamic-attributes/{id}, GET /employees, POST /employees, GET /employees/{username}, PATCH /employees/{username}, PUT /employees/{username}, GET /employees/{username}/absences, GET /employees/{username}/employment-periods, POST /employees/{username}/employment-periods, GET /employees/{username}/employment-periods/{id}, PATCH /employees/{username}/employment-periods/{id}, PUT /employees/{username}/employment-periods/{id}, GET /employees/{username}/internal-rates, GET /employees/{username}/internal-rates/{id}, GET /employees/{username}/meals, GET /employees/{username}/meals/{id}, GET /employees/{username}/projects, GET /employees/{username}/regular-working-times, POST /employees/{username}/regular-working-times, GET /employees/{username}/regular-working-times/{id}, PATCH /employees/{username}/regular-working-times/{id}, PUT /employees/{username}/regular-working-times/{id}, GET /employees/{username}/transponders, GET /folders, GET /folders/{id}, GET /folders/{id}/documents, GET /folders/{id}/documents/{document_id}, GET /invoice-items, GET /invoice-items/{id}, GET /invoices, GET /invoices/{invoice_number}, GET /invoices/{invoice_number}/attachments, GET /invoices/{invoice_number}/items, GET /location-lists, GET /location-lists/{id}, GET /location-lists/{id}/locations, GET /locations, GET /locations/{name}, GET /offers, GET /offers/{id}, GET /offers/{id}/items, GET /offers/{id}/items/{item_id}, GET /planning, GET /plannings, GET /price-groups, GET /price-groups/{id}, GET /projects, POST /projects, DELETE /projects/{id}, GET /projects/{id}, PATCH /projects/{id}, PUT /projects/{id}, GET /projects/{id}/activities, GET /projects/{id}/employees, GET /projects/{id}/invoice-items, GET /projects/{id}/locations, GET /projects/{id}/price-tables, GET /projects/{id}/price-tables/{price_table_id}, GET /projects/{id}/tasks, POST /projects/{id}/tasks, DELETE /projects/{id}/tasks/{task_id}, GET /projects/{id}/tasks/{task_id}, PATCH /projects/{id}/tasks/{task_id}, PUT /projects/{id}/tasks/{task_id}, GET /projects/{id}/tasks/{task_id}/employees, GET /projects/{id}/tasks/{task_id}/employees/{project_task_employee_id}, GET /receipts, POST /receipts, GET /receipts-amounts, DELETE /receipts/{id}, GET /receipts/{id}, PATCH /receipts/{id}, PUT /receipts/{id}, GET /receipts/{id}/amounts, GET /receipts/{id}/amounts/{amount_id}, DELETE /receipts/{id}/attachments, GET /receipts/{id}/attachments, PUT /receipts/{id}/attachments, GET /resource-plannings, GET /tickets, POST /tickets, DELETE /tickets/{id}, GET /tickets/{id}, PATCH /tickets/{id}, PUT /tickets/{id}, POST /tickets/{id}/attachments, GET /tickets/{id}/subtasks, POST /tickets/{id}/subtasks, DELETE /tickets/{id}/subtasks/{subtask_id}, GET /tickets/{id}/subtasks/{subtask_id}, PATCH /tickets/{id}/subtasks/{subtask_id}, PUT /tickets/{id}/subtasks/{subtask_id}, GET /vehicles, GET /workhour-balances, GET /workhour-balances/{id}: added the non-success response with the status 429
  • INFO POST /absences: removed subschema #1, subschema #2 from the response body anyOf list for the response status 201
  • INFO POST /absences: the response’s body type was narrowed from any to object for status 201
  • NEU POST /absences, POST /attendances, POST /customers, POST /customers/{customer_number}/contacts, POST /employees, POST /employees/{username}/employment-periods, POST /employees/{username}/regular-working-times, POST /projects, POST /projects/{id}/tasks: the response header x-ratelimit-limit was added for the status 201
  • NEU POST /absences, POST /attendances, POST /customers, POST /customers/{customer_number}/contacts, POST /employees, POST /employees/{username}/employment-periods, POST /employees/{username}/regular-working-times, POST /projects, POST /projects/{id}/tasks: the response header x-ratelimit-remaining was added for the status 201
  • NEU POST /absences: added the non-success response with the status 502
  • NEU POST /absences: added the optional property code to the response with the 422 status
  • NEU POST /absences: added the optional property status to the response with the 422 status
  • NEU POST /absences: added the required property data to the response with the 201 status
  • INFO GET /attendances: the data/items/end_date response’s property format was narrowed from none to date for status 200
  • INFO POST /attendances: the data/end_date response’s property format was narrowed from none to date for status 201
  • INFO GET /attendances/{id}, PATCH /attendances/{id}, PUT /attendances/{id}: the data/end_date response’s property format was narrowed from none to date for status 200
  • INFO GET /departments, GET /departments/{id}/children: the data/items/id response’s property type was narrowed from any to integer for status 200
  • INFO GET /departments/{id}: the data/id response’s property type was narrowed from any to integer for status 200
  • NEU GET /departments/{id}/employees, GET /employees: added the optional property data/items/employment_periods to the response with the 200 status
  • NEU GET /departments/{id}/employees, GET /employees: added the optional property data/items/internal_rates to the response with the 200 status
  • NEU GET /departments/{id}/employees, GET /employees: added the optional property data/items/regular_working_times to the response with the 200 status
  • INFO GET /departments/{id}/employees, GET /employees: removed the “ enum value from the data/items/salutation/name response property for the response status 200
  • INFO GET /departments/{id}/employees, GET /employees: removed the Frau enum value from the data/items/salutation/name response property for the response status 200
  • INFO GET /departments/{id}/employees, GET /employees: removed the Herr enum value from the data/items/salutation/name response property for the response status 200
  • NEU GET /departments/{id}/employees, GET /employees: added the required property data/items/cost_center to the response with the 200 status
  • NEU GET /departments/{id}/employees, GET /employees, GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/note to the response with the 200 status
  • NEU GET /departments/{id}/employees, GET /employees: added the required property data/items/overtime_ads to the response with the 200 status
  • NEU GET /employees, GET /employees/{username}, GET /invoices: added the new optional query request parameter include
  • NEU POST /employees: added the optional property data/allOf[subschema #1: EmployeeResource]/employment_periods to the response with the 201 status
  • NEU POST /employees: added the optional property data/allOf[subschema #1: EmployeeResource]/internal_rates to the response with the 201 status
  • NEU POST /employees: added the optional property data/allOf[subschema #1: EmployeeResource]/regular_working_times to the response with the 201 status
  • INFO POST /employees: removed the “ enum value from the data/allOf[subschema #1: EmployeeResource]/salutation/name response property for the response status 201
  • INFO POST /employees: removed the Frau enum value from the data/allOf[subschema #1: EmployeeResource]/salutation/name response property for the response status 201
  • INFO POST /employees: removed the Herr enum value from the data/allOf[subschema #1: EmployeeResource]/salutation/name response property for the response status 201
  • NEU POST /employees: added the required property data/allOf[subschema #1: EmployeeResource]/cost_center to the response with the 201 status
  • NEU POST /employees: added the required property data/allOf[subschema #1: EmployeeResource]/note to the response with the 201 status
  • NEU POST /employees: added the required property data/allOf[subschema #1: EmployeeResource]/overtime_ads to the response with the 201 status
  • NEU GET /employees/{username}, GET /employees/{username}/employment-periods, GET /employees/{username}/internal-rates, GET /employees/{username}/regular-working-times: added the non-success response with the status 422
  • NEU GET /employees/{username}: added the optional property data/employment_periods to the response with the 200 status
  • NEU GET /employees/{username}: added the optional property data/internal_rates to the response with the 200 status
  • NEU GET /employees/{username}: added the optional property data/regular_working_times to the response with the 200 status
  • INFO GET /employees/{username}: removed the “ enum value from the data/salutation/name response property for the response status 200
  • INFO GET /employees/{username}: removed the Frau enum value from the data/salutation/name response property for the response status 200
  • INFO GET /employees/{username}: removed the Herr enum value from the data/salutation/name response property for the response status 200
  • NEU GET /employees/{username}: added the required property data/cost_center to the response with the 200 status
  • NEU GET /employees/{username}: added the required property data/note to the response with the 200 status
  • NEU GET /employees/{username}: added the required property data/overtime_ads to the response with the 200 status
  • NEU PATCH /employees/{username}, PUT /employees/{username}: added the optional property data/allOf[subschema #1: EmployeeResource]/employment_periods to the response with the 200 status
  • NEU PATCH /employees/{username}, PUT /employees/{username}: added the optional property data/allOf[subschema #1: EmployeeResource]/internal_rates to the response with the 200 status
  • NEU PATCH /employees/{username}, PUT /employees/{username}: added the optional property data/allOf[subschema #1: EmployeeResource]/regular_working_times to the response with the 200 status
  • INFO PATCH /employees/{username}, PUT /employees/{username}: removed the “ enum value from the data/allOf[subschema #1: EmployeeResource]/salutation/name response property for the response status 200
  • INFO PATCH /employees/{username}, PUT /employees/{username}: removed the Frau enum value from the data/allOf[subschema #1: EmployeeResource]/salutation/name response property for the response status 200
  • INFO PATCH /employees/{username}, PUT /employees/{username}: removed the Herr enum value from the data/allOf[subschema #1: EmployeeResource]/salutation/name response property for the response status 200
  • NEU PATCH /employees/{username}, PUT /employees/{username}: added the required property data/allOf[subschema #1: EmployeeResource]/cost_center to the response with the 200 status
  • NEU PATCH /employees/{username}, PUT /employees/{username}: added the required property data/allOf[subschema #1: EmployeeResource]/note to the response with the 200 status
  • NEU PATCH /employees/{username}, PUT /employees/{username}: added the required property data/allOf[subschema #1: EmployeeResource]/overtime_ads to the response with the 200 status
  • NEU GET /employees/{username}/employment-periods, GET /employees/{username}/internal-rates, GET /employees/{username}/regular-working-times: added the new optional query request parameter limit
  • INFO GET /employees/{username}/projects, GET /folders/{id}/documents, GET /projects/{id}/employees: removed subschema #1, subschema #2 from the data/items/ response property anyOf list for the response status 200
  • INFO GET /employees/{username}/projects, GET /folders/{id}/documents, GET /projects/{id}/employees: the data/items/ response’s property type was narrowed from any to object for status 200
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/availability to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/employee_id to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/from to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /folders/{id}/documents, GET /projects/{id}/employees: added the required property data/items/id to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/internal_rate to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/priceGroup to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/project_id to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/project_number to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/rate_type to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/to to the response with the 200 status
  • NEU GET /employees/{username}/projects, GET /projects/{id}/employees: added the required property data/items/type to the response with the 200 status
  • NEU GET /folders/{id}/documents: added the required property data/items/file_contents to the response with the 200 status
  • NEU GET /folders/{id}/documents: added the required property data/items/file_type to the response with the 200 status
  • NEU GET /folders/{id}/documents: added the required property data/items/filename to the response with the 200 status
  • INFO GET /folders/{id}/documents/{document_id}: removed subschema #1, subschema #2 from the data response property anyOf list for the response status 200
  • INFO GET /folders/{id}/documents/{document_id}: the data response’s property type was narrowed from any to object for status 200
  • NEU GET /folders/{id}/documents/{document_id}: added the required property data/file_contents to the response with the 200 status
  • NEU GET /folders/{id}/documents/{document_id}: added the required property data/file_type to the response with the 200 status
  • NEU GET /folders/{id}/documents/{document_id}: added the required property data/filename to the response with the 200 status
  • NEU GET /folders/{id}/documents/{document_id}: added the required property data/id to the response with the 200 status
  • NEU GET /invoices: added the new optional query request parameter end_date
  • NEU GET /invoices: added the new optional query request parameter modified_after
  • NEU GET /invoices: added the new optional query request parameter modified_before
  • NEU GET /invoices: added the new optional query request parameter start_date
  • NEU GET /invoices: added the optional property data/items/items to the response with the 200 status
  • NEU GET /invoices/{invoice_number}: added the optional property data/items to the response with the 200 status
  • NEU GET /plannings: added the optional property data/items/planning_details/effective_hours to the response with the 200 status
  • NEU GET /plannings: added the optional property data/items/planning_details/from_time to the response with the 200 status
  • NEU GET /plannings: added the optional property data/items/planning_details/to_time to the response with the 200 status
  • INFO GET /plannings: removed subschema #1, subschema #2 from the data/items/planning_details response property anyOf list for the response status 200
  • INFO GET /plannings: the data/items/planning_details response’s property type was narrowed from any to object for status 200
  • NEU GET /plannings: added the required property data/items/planning_details/type to the response with the 200 status
  • NEU GET /plannings: added the required property data/items/planning_details/unit to the response with the 200 status
  • NEU GET /plannings: added the required property data/items/planning_details/value to the response with the 200 status
  • NEU GET /project-employees: endpoint added
  • INFO GET /projects: the data/items/keywords/items/ response’s property type was narrowed from any to string for status 200
  • INFO POST /projects: the data/allOf[subschema #1: ProjectResource]/keywords/items/ response’s property type was narrowed from any to string for status 201
  • INFO GET /projects/{id}: the data/keywords/items/ response’s property type was narrowed from any to string for status 200
  • INFO PATCH /projects/{id}, PUT /projects/{id}: the data/allOf[subschema #1: ProjectResource]/keywords/items/ response’s property type was narrowed from any to string for status 200
  • NEU GET /projects/{id}/tasks: added the required property data/items/all_project_employees to the response with the 200 status
  • NEU POST /projects/{id}/tasks: added the required property data/allOf[subschema #1: ProjectTaskResource]/all_project_employees to the response with the 201 status
  • NEU GET /projects/{id}/tasks/{task_id}: added the required property data/all_project_employees to the response with the 200 status
  • NEU PATCH /projects/{id}/tasks/{task_id}, PUT /projects/{id}/tasks/{task_id}: added the required property data/allOf[subschema #1: ProjectTaskResource]/all_project_employees to the response with the 200 status
  • INFO GET /projects/{id}/tasks/{task_id}/employees: the data/items/from response’s property format was narrowed from none to date for status 200
  • INFO GET /projects/{id}/tasks/{task_id}/employees: the data/items/to response’s property format was narrowed from none to date for status 200
  • INFO GET /projects/{id}/tasks/{task_id}/employees/{project_task_employee_id}: the data/from response’s property format was narrowed from none to date for status 200
  • INFO GET /projects/{id}/tasks/{task_id}/employees/{project_task_employee_id}: the data/to response’s property format was narrowed from none to date for status 200

v8.0.27 · OpenAPI 1.0.0 · 22.10.2026

Search combines with the other filters: GET /projects, GET /projects/{id}/tasks

search matches the name or the description, and both now apply together with the other filters (project, status, …). Before, a match on the description or name bypassed them, so GET /projects/12/tasks?search=meeting also returned tasks of other projects. No contract change.

v8.0.24 · OpenAPI 1.0.0 · 22.10.2026

Contacts without primary: POST /customers/{customer_number}/contacts, PUT/PATCH /customers/{customer_number}/contacts/{id}

Creating a contact with primary set to null answered 500. A contact created without primary — null or left out — now becomes the customer’s primary contact when the customer has none yet, and a secondary one otherwise, as in ZEP; before, a left-out primary was stored empty and read back as null. Updating with primary: null keeps the contact’s current value instead of clearing it. No contract change.

Error body when ZEP rejects a write: POST /receipts, PUT/PATCH /receipts/{id}, POST /tickets, PUT/PATCH /tickets/{id}, POST /tickets/{id}/subtasks, PUT/PATCH /tickets/{id}/subtasks/{subtask_id}

When ZEP rejected the write without an error text, these endpoints answered a bare 500 instead of the documented {"success": false, "message": …}. They now always answer with that body: message is ZEP’s text, or “The request could not be processed.” when ZEP sent none. The status stays 500. No contract change.

Project billability and billing type on update: PUT/PATCH /projects/{project}

default_billability: null answered 500. It now keeps the project’s current default billability, the same as leaving the field out. An unknown value (99, "foo", {"id": 99}) for default_billability also answered 500; for billing_type and receipts_billability it was accepted and cleared the field. All three now reject it with 422 and a validation error on the field. No contract change.

v8.0.17 · OpenAPI 1.0.0 · 13.10.2026

Fahrzeuge: GET /vehicles

Listet die Fahrzeuge einer Fahrzeugliste; die id ist das Kürzel, das Projektzeiten als vehicle_id tragen. Fahrzeuge liegen in datierten Listen; gültig ist an date (YYYY-MM-DD, Standard heute) die Liste mit dem spätesten Startdatum an oder vor diesem Tag. Vor der ersten Liste ist die Antwort leer. Paginiert über limit, nur lesend. Auf ZEP Clock nicht verfügbar.

Rechnungsersteller: GET /invoices, GET /invoices/{invoice}

Jede Rechnung trägt jetzt creator_username, den Benutzernamen des Mitarbeiters, der das Rechnungsdokument erstellt hat – der Mitarbeiter, den ZEP auf der Rechnung zeigt. Nach einer Korrektur ist es der Mitarbeiter, der die Rechnung korrigiert hat; null, wenn kein Rechnungsdokument gespeichert ist.

Projektzeiten akzeptieren das Fahrzeug-Kürzel: POST /attendances, PATCH /attendances/{id}

vehicle_id ist das Kürzel des Fahrzeugs (so wie GET es schon liefert, z. B. PKW), ein String mit höchstens 32 Zeichen. Bisher wurde es mit „must be a number“ abgelehnt; eine Zahl hat nur bei numerischen Kürzeln funktioniert und tut das weiterhin (sie wird als Kürzel gelesen). Bitte das Kürzel als String senden.

Die Typänderung von vehicle_id ist als Korrektur geführt, nicht als brechende Änderung: Die Anfrage hat vorher gar kein Fahrzeug angenommen (jeder Wert wurde abgelehnt), daher hängt keine funktionierende Integration am alten Typ. Eine Zahl, die einem numerischen Kürzel entspricht, wird weiterhin angenommen.

Alle Einzeländerungen (5)
  • KORREKTUR POST /attendances, PATCH /attendances/{id}, PUT /attendances/{id}: the vehicle_id request property type changed from number, null to string, null
  • INFO POST /attendances, PATCH /attendances/{id}, PUT /attendances/{id}: the vehicle_id request property’s maxLength was set to 32
  • NEU GET /invoices: added the required property data/items/creator_username to the response with the 200 status
  • NEU GET /invoices/{invoice_number}: added the required property data/creator_username to the response with the 200 status
  • NEU GET /vehicles: endpoint added

v8.0.15 · OpenAPI 1.0.0 · 12.10.2026

Task description limited to 255 characters: POST /projects/{id}/tasks, PUT/PATCH /projects/{id}/tasks/{task_id}

A description longer than 255 characters answered 500, because the task’s description holds at most 255. It is now rejected with 422 and a validation error on description, and the request schema declares maxLength: 255.

Alle Einzeländerungen (1)
  • INFO POST /projects/{id}/tasks, PATCH /projects/{id}/tasks/{task_id}, PUT /projects/{id}/tasks/{task_id}: the description request property’s maxLength was set to 255

v8.0.11 · OpenAPI 1.0.0 · 10.10.2026

List endpoints sort by orderBy and order

Most list endpoints accepted both parameters and ignored them, so GET /offers?orderBy=status came back in id order. Every list endpoint that documents them now sorts by the record’s key, its writable fields or created/modified, named as in the response (status, name, valid_until, …), order asc or desc. Records with the same value follow in key order (resource plannings: start date, employee, id), so paging stays stable, and links keep the sort. Any other orderBy value sorts by the default, the key (name for locations, the start date for resource plannings); before, it answered 500 on the location, location list and dynamic attribute definition lists. GET /plannings keeps its date order, and GET /projects/{project}/employees its own. No contract change.

v8.0.10 · OpenAPI 1.0.0 · 06.10.2026

GET /resource-plannings liefert die Planungen der Ressourcenplanung: Zeitraum, Einheit (percent oder hours pro Tag) und Wert, dazu die geplanten Stunden je Kalendermonat und gesamt. Filterbar nach date_from/date_to, employee_ids[], project_ids[], customer_numbers[] und modified_after/modified_before. Nur mit dem Modul Ressourcenplanung (MOD_PLANNING_NEXT oder Produktlinie 4 ohne MOD_RESSOURCENPLANUNG); andere Mandanten erhalten 404. GET /plannings bleibt unverändert.

Alle Einzeländerungen (1)
  • NEU GET /resource-plannings: endpoint added

v8.0.9 · OpenAPI 1.0.0 · 06.10.2026

Die REST-API steht auf jeder ZEP-Produktlinie (Produktwelt 2026) ohne das separate Modul MOD_SOAP zur Verfügung; Mandanten mit Produktlinie erhielten vorher 404. Lizenzen ohne Produktlinie brauchen weiterhin MOD_SOAP. Der Vertrag selbst hat sich nicht geändert.

v8.0.7 · OpenAPI 1.0.0 · 25.09.2026 — die generierte Spezifikation wird maßgeblich

  • INFO Das OpenAPI-Dokument wird bei jedem Release aus dem Code (Controller, Form Requests, Resources) erzeugt und hier unverändert veröffentlicht — dieselbe Datei, die die interaktive Referenz rendert. Beschreibungen stehen neben dem Feld, das sie beschreiben, und können nicht mehr auseinanderlaufen.
  • INFO Versionsschema: info.version ist 1.0.0 und folgt ab jetzt dem Vertrag. Die bisherigen Nummern (7.12.49 und älter) spiegelten die ZEP-Produktversion.
  • INFO Alle Referenzseiten dieser Dokumentation (und diese Navigation) werden aus der Spezifikation erzeugt, auf Deutsch und Englisch. Die Antwortbeispiele sind die Feldbeispiele der Spezifikation.
  • INFO Für ZEP Clock wird eine eigene Spezifikation neben der Vollversion veröffentlicht; die Referenzseite hat einen Umschalter, und jede Endpunktseite sagt, ob der Endpunkt auf einer Clock-Instanz verfügbar ist.
  • NEU Alle Update-Operationen akzeptieren PUT als Alias von PATCH — der Router tat das immer, die Dokumentation sagt es jetzt.
  • ABGEKÜNDIGT GET Planung (Legacy-Alias): GET /planning leitet auf GET /plannings um und antwortet mit den Headern Deprecation, Sunset (2027-08-31) und Link. Der Alias wird frühestens am 2027-08-31 entfernt.
  • ABGEKÜNDIGT Kunden: das Objekt status trägt in der Spezifikation deprecated: true und x-sunset: 2027-08-31. Lesen Sie stattdessen inactive; status ist nicht Teil von API v2.
  • FIX Strengere Eingabeprüfung für Anfragen, die vorher kein brauchbares Ergebnis geliefert haben: POST /attendances, PATCH /attendances/{id} und PUT /attendances/{id} nehmen date nur noch als JJJJ-MM-TT (eine Uhrzeit endete in einem Serverfehler, 500); GET /departments lehnt ein leeres start_date oder end_date ab (das ergab nie einen korrekten Filter). Beides antwortet jetzt mit 422; Clients, die bereits reine Datumswerte senden, sind nicht betroffen.
  • FIX Pfadparameter heißen nach dem Schlüssel, über den die API auflöst: /absence-reasons/{name}, /activities/{activity}, /categories/{name}, /customers/{customer_number}/contacts/{id}, /invoices/{invoice_number}. Numerische IDs haben dort nie funktioniert; die Dokumentation behauptete es.
  • FIX created und modified sind an jeder Ressource dokumentiert statt created_at / updated_at, die die API nie geliefert hat.
  • FIX Regelarbeitszeiten liefern holidayCalendar und breakRegulationType mit den englischen Feldnamen, die die API immer zurückgegeben hat (name, note, country, region), nicht mit den deutschen Spaltennamen des alten Dokuments.
  • FIX Nullability und Pflichtfelder jeder Antwort entsprechen den echten Antworten (an einer laufenden Instanz gemessen), und der Filter status[] der Rechnungspositions-Endpunkte deklariert seine Werte als Ganzzahlen.

v7.12.49 (24.07.2026)

Fasst alle Änderungen seit v7.12 (22.06.2026) zusammen.

  • FIX POST Projektzeit anlegen: Die Buchungsregeln werden jetzt vor dem Schreiben geprüft, Verstöße kommen als 422 mit Meldungen je Feld zurück — abgeschlossener Monat, überschrittenes Freigabedatum, Erfassungszeitraum, Nichtarbeitstag oder Feiertag, Beschäftigungszeitraum, Laufzeit von Projekt, Vorgang oder Ticket, überschrittene Planstunden. Die Schnittstelle hat solche Buchungen bisher als einzige angenommen; Weboberfläche, SOAP und Clock lehnen sie seit jeher ab. Wer gültig bucht, merkt nichts.
  • FIX Projektzeiten: Eine Buchung, die um 00:00 endet, gehört zum Folgetag. Diese Grenze geht jetzt in die Überschneidungsprüfung ein, Doppelbuchungen über die Tagesgrenze werden dadurch erkannt und abgelehnt.
  • FIX GET Kunden: status bleibt erhalten und meldet jetzt den tatsächlichen Zustand. Zuvor kam ein inaktiver Kunde als { "value": 1, "label": "Active" } zurück, obwohl die Dokumentation immer 1 = aktiv sagte. Für aktive Kunden ändert sich nichts; wer die Umkehrung im eigenen Client ausgeglichen hat, entfernt diesen Ausgleich.
  • VERALTET Kunden: inactive (boolean) ersetzt status. status wird weiterhin ausgeliefert und bei POST und PATCH akzeptiert; werden beide gesendet, gewinnt inactive. Der Filter ?status= ist ebenfalls veraltet, Ersatz ist ?inactive=. Ein Abkündigungsdatum wird gesondert angekündigt.
  • NEU PATCH Projektzeit aktualisieren
  • NEU DELETE Projektzeit löschen: Prüft die Sperrfristen — abgeschlossener Monat, Freigabedatum, Erfassungszeitraum
  • NEU POST Ansprechpartner anlegen
  • NEU GET Ansprechpartner abrufen
  • NEU PATCH Ansprechpartner aktualisieren
  • NEU DELETE Ansprechpartner löschen
  • NEU PATCH Projektvorgang aktualisieren
  • NEU Projektzeiten: end_date in jeder Antwort — der Kalendertag, an dem die Buchung endet. to allein ist bei einer Buchung bis Tagesende mehrdeutig, weil sie als to = 00:00:00 am Starttag gespeichert wird.
  • NEU Ansprechpartner: department und categories in der Antwort
  • NEU Die Filter modified_after und modified_before auf mehreren Listen-Endpunkten
  • NEU Die Sprachen sk (Slowakisch) und tr (Türkisch)
  • FIX Ein leerer Datumsfilter liefert 422 statt 500 — bei Abwesenheiten und fünf weiteren Endpunkten
  • FIX Mitarbeiter, deren Beschäftigungszeitraum kein Anfangs- oder Enddatum hat, werden nicht mehr als „außerhalb des Beschäftigungszeitraums” abgelehnt. Eine fehlende Grenze bedeutet jetzt offen.
  • FIX default_billability und receipts_billability werden bei POST und PATCH nicht mehr ignoriert
  • FIX Planung: Die konfigurierten Vorgabewerte werden zurückgegeben
  • INFO Neun Operationen, die es längst gab, sind jetzt beschrieben — unter anderem POST /absences, GET /attendances/:id und PATCH /employees/:username. Dazu 66 Felder, die Antworten schon immer enthielten, und zwei Beziehungsschlüssel bei den regulären Arbeitszeiten, die nie so hießen wie dokumentiert.

v7.12 (22.06.2026)

v7.8.74 (09.01.2026)

v7.8.64 (07.01.2026)

  • NEU POST Beleg erstellen: Endpunkt zum Erstellen von Belegen hinzugefügt
  • NEU PATCH Beleg aktualisieren: Endpunkt zum Aktualisieren von Belegen hinzugefügt
  • NEU DELETE Beleg löschen: Endpunkt zum Löschen von Belegen hinzugefügt
  • NEU PUT Anhang hochladen: Endpunkt zum Hochladen von Beleganhängen hinzugefügt
  • NEU DELETE Anhang löschen: Endpunkt zum Löschen von Beleganhängen hinzugefügt

v7.7.0 (07.10.2025)

  • NEU GET Artikel: Endpunkt zum Abrufen von Artikeln hinzugefügt
  • NEU GET Artikel-Details: Endpunkt für einzelnen Artikel hinzugefügt
  • NEU GET Planung: Endpunkt zum Abrufen von Planungseinträgen hinzugefügt
  • NEU GET Projekt-Standorte: Endpunkt für Standorte eines Projekts hinzugefügt
  • NEU PUT Mitarbeiter aktualisieren: Endpunkt zum Aktualisieren von Mitarbeitern hinzugefügt
  • NEU PUT Beschäftigungszeitraum aktualisieren: Endpunkt zum Aktualisieren von Beschäftigungszeiträumen hinzugefügt
  • FIX Korrektur Datentyp plan_can_exceed von boolean zu enum (0-4) in allen Projekt-Endpunkten
  • FIX Fehlende Filterparameter (project_status, project_start_date, project_end_date) für Mitarbeiterprojekte hinzugefügt
  • FIX Fehlendes id Feld in ProjectEmployee Response-Beispielen ergänzt

v7.6.1 (22.09.2025)

v7.4.2 (24.06.2025)

  • NEU GET Projektzeiten: Neue Felder project_release, project_released_at und project_released_by für die Projektzeitfreigabe hinzugefügt
  • NEU GET Projektzeit-Details: Neue Felder für die Projektzeitfreigabe hinzugefügt

v7.4.1 (18.06.2025)

  • INFO OpenAPI-Spezifikation aktualisiert, um alle dokumentierten Endpunkte einzuschließen
  • NEU POST Mitarbeiter erstellen
  • FIX GET Abwesenheiten: Response-Beispiele an aktuelle API-Struktur angepasst, inklusive neuer Felder absence_reason_id, absenceReason Objekt und korrigierte Datumsformate
  • FIX GET Projektzeiten: Response-Beispiele an aktuelle API-Struktur angepasst, Datums-/Zeitformate aktualisiert
  • NEU GET Projektzeit-Details: Dokumentation für einzelne Projektzeit hinzugefügt
  • FIX GET Abteilungen: Response-Beispiele mit neuen Feldern parent_id, manager_count, children_count aktualisiert
  • FIX GET Abteilungs-Details: Response-Struktur mit manager Array statt manager_count aktualisiert
  • FIX GET Abteilungs-Mitarbeiter: Response-Beispiele mit neuem Feld approval_date und Language-Objektstruktur aktualisiert
  • FIX GET Mitarbeiter: Neue Felder categories und dynamicAttributes Arrays hinzugefügt, release_date zu approval_date geändert
  • NEU GET Mitarbeiter-Transponder: Dokumentation für das Abrufen von RFID-Transpondern eines Mitarbeiters hinzugefügt
  • FIX GET Terminals: Response-Beispiele an aktuelle API-Struktur mit Gerätetypen und Statuscodes angepasst
  • FIX GET Terminal-Details: Response-Struktur mit employees und categories Arrays aktualisiert
  • FIX GET Kunden: Response-Struktur mit neuen Feldern vat (ersetzt tax), status als Objekt, department_id, categories und dynamicAttributes Arrays aktualisiert
  • FIX GET Kunden-Details: Response mit neuen Adressfeldern aktualisiert, employees Array entfernt, vollständige priceTables Struktur hinzugefügt
  • FIX GET Angebote: Response-Beispiele aktualisiert und fehlendes Feld order_probability_percent hinzugefügt
  • NEU GET Angebotspositionen: Dokumentation für das Abrufen von Angebotspositionen hinzugefügt
  • FIX GET Belege: Response-Struktur mit vereinfachter receipt_type_id als String statt Objekt aktualisiert, Feldnamen is_amount_gross_or_net zu is_amount_net und is_invoice_amount_gross_or_net zu is_invoice_amount_net geändert
  • FIX GET Beleg-Details: Response-Struktur an Listen-Endpunkt mit gleichen Feldänderungen angepasst
  • FIX GET Beleg-Beträge: Response-Beispiele mit realistischen Daten aktualisiert und neue Felder is_amount_net und is_invoice_amount_net hinzugefügt
  • FIX GET Beleg-Anhänge: Response-Beispiel mit Base64-codierten Dateiinhalten hinzugefügt
  • FIX GET Tickets: Response-Beispiele korrigiert - enthielten fälschlicherweise Belegdaten statt Ticketdaten, categories Array hinzugefügt
  • FIX GET Ticket-Details: Response-Beispiel mit aktuellen Daten aktualisiert
  • FIX GET Ticket-Teilaufgaben: Response-Beispiel mit realistischen Daten aktualisiert
  • FIX GET Ticket-Teilaufgabe Details: Response-Beispiel mit anonymisierten Daten aktualisiert, Überschrift korrigiert
  • NEU GET Ordner: Neuer Endpunkt zum Abrufen von Ordnern hinzugefügt
  • NEU GET Ordner-Dokumente: Neuer Endpunkt zum Abrufen von Dokumenten innerhalb eines Ordners
  • NEU GET Preisgruppen: Neuer Endpunkt zum Abrufen von Preisgruppen hinzugefügt
  • NEU GET Tätigkeiten: Neuer Endpunkt zum Abrufen von Tätigkeiten hinzugefügt
  • NEU GET Fehlgründe: Neuer Endpunkt zum Abrufen von Fehlgründen hinzugefügt
  • NEU GET Kategorien: Neuer Endpunkt zum Abrufen von Kategorien hinzugefügt

v7.4.0 (17.06.2025)

  • NEU Hauptversion-Update mit erweiterten API-Funktionen
  • INFO Aktualisierte API-Dokumentation und verbesserte Endpunkt-Beschreibungen

v6.13.17 (16.09.2024)

v6.13.16 (27.08.2024)

v6.12.5 (06.03.2024)

  • INFO Das Rate-Limiting wurde auf 12000 Requests pro Stunde erhöht. Pro 5 Minuten sind maximal 1000 Requests erlaubt
  • NEU GET Projekte Projektfilter um den Parameter name erweitert
  • FIX GET Projekte: Der Wert plan_hours zeigte keine Planstunden, wenn diese in Vorgängen definiert wurden. Hierzu wurde nun der Wert plan_hours_children hinzugefügt
  • FIX GET Projekte: Das Projekt muss nun nicht mehr komplett innerhalb eines gefilterten Zeitraums liegen. Es reicht, wenn es innerhalb des Zeitraums aktiv war
  • FIX GET Mitarbeiter: Unter bestimmten Umständen trat ein Server Error auf. Dieser Fehler wurde behoben

v6.12.4 (01.03.2024)

  • INFO Kleinere Optimierung der Performance

v6.12.3 (16.02.2024)

v6.12.2 (02.02.2024)

v6.12.1 (14.01.2024)