API
REST API for the Timebutler HR SaaS. Used by integrators for absence, time tracking, substitute, and user profile workflows. All endpoints except /oauth2/token require a bearer JWT access token.
OAuth 2.0 token endpoint. Issues JWT access tokens and rotating refresh tokens. This endpoint is public — no bearer token is required.
As an alternative to the OAuth 2.0 password flow, individual users can create personal access tokens. Tokens are long-lived, named, revocable, and scoped to a single user — no password sharing or refresh-token rotation required.
Tokens have the prefix tb_ followed by an opaque, URL-safe Base64 string. Send them in the Authorization header just like any other bearer credential:
curl "https://app.timebutler.com/api/v2/timeentry/pendingcount" \ -H "Authorization: Bearer tb_a1b2c3d4e5f6..."
/oauth2/tokenIssue or refresh a token
Supports five grant types: **`grant_type=password`** — authenticates with `username` and `password`. Returns an access token and refresh token on success. If the account has 2FA enabled, returns an MFA challenge (`mfa_required=true`, `mfa_token`, `mfa_expires_in`) instead — complete the flow with `grant_type=mfa_totp`. **`grant_type=refresh_token`** — exchanges a valid `refresh_token` for a new access token and rotates the refresh token (each refresh token can be used exactly once). **`grant_type=mfa_totp`** — second step of the 2FA flow. Submit the `mfa_token` from the password-grant challenge together with the current `totp_code` from the user's authenticator app. Returns an access token and refresh token on success. **`grant_type=sso_id_token`** — single sign-on via an ID token the mobile app already obtained from the SSO provider. Submit `provider=google` and the provider's `id_token` (a JWT). Timebutler verifies the JWT's signature, issuer and audience and returns an access token and refresh token for the linked Timebutler account. **`grant_type=sso_code`** — single sign-on via an authorization code the mobile app obtained from the SSO provider's consent screen. Submit `provider=microsoft` or `provider=slack`, the `code` from the provider, and the exact `redirect_uri` used in the authorize request. For Microsoft public-client app registrations, also send the PKCE `code_verifier` whose SHA-256 hash was used as `code_challenge` in the authorize step. Timebutler exchanges the code with the provider, identifies the user and returns the token pair. All grant types also require `client_id`. Use `client_id=public` to authenticate without a secret, or supply both `client_id` and `client_secret` for a registered confidential client.
| Name | Type | Description |
|---|---|---|
| grant_type | string | OAuth 2.0 grant type. Supported values: `password`, `refresh_token`, `mfa_totp`, `sso_id_token`, `sso_code`. |
| username | string | User's email address. Required for `grant_type=password`. |
| password | string | User's password. Required for `grant_type=password`. |
| refresh_token | string | Refresh token obtained from a previous token response. Required for `grant_type=refresh_token`. |
| client_id | string | Client identifier. Use `public` for unauthenticated public clients. |
| client_secret | string | Client secret. Required for confidential clients; omit when using `client_id=public`. |
| mfa_token | string | MFA challenge token received from a `password` grant when 2FA is required. Required for `grant_type=mfa_totp`. |
| totp_code | string | Current TOTP code from the user's authenticator app. Required for `grant_type=mfa_totp`. |
| provider | string | SSO provider identifier. Required for `grant_type=sso_id_token` (`google`) and `grant_type=sso_code` (`microsoft`, `slack`). |
| id_token | string | SSO ID token issued by the provider (e.g. a Google ID token JWT). Required for `grant_type=sso_id_token`. |
| code | string | Authorization code returned by the SSO provider's authorize endpoint. Required for `grant_type=sso_code`. |
| redirect_uri | string | Redirect URI that was used when obtaining the authorization code. Must match the value registered with the SSO provider. Required for `grant_type=sso_code`. |
| code_verifier | string | PKCE code verifier — the plaintext value whose SHA-256 hash was sent as `code_challenge` in the authorization request. Required for `grant_type=sso_code` when the SSO provider's app registration is a public client (e.g. Microsoft Azure AD mobile app). |
{ }
| Name | Type | Description |
|---|---|---|
| error | string | OAuth 2.0 error code (e.g. `invalid_grant`, `invalid_client`). |
| error_description | string | Human-readable description of the error. |
{
"error" : "invalid_grant",
"error_description" : "Invalid username or password"
}
| Name | Type | Description |
|---|---|---|
| error | string | OAuth 2.0 error code (e.g. `invalid_grant`, `invalid_client`). |
| error_description | string | Human-readable description of the error. |
{
"error" : "invalid_grant",
"error_description" : "Invalid username or password"
}
| Name | Type | Description |
|---|---|---|
| error | string | OAuth 2.0 error code (e.g. `invalid_grant`, `invalid_client`). |
| error_description | string | Human-readable description of the error. |
{
"error" : "invalid_grant",
"error_description" : "Invalid username or password"
}
| Name | Type | Description |
|---|---|---|
| error | string | OAuth 2.0 error code (e.g. `invalid_grant`, `invalid_client`). |
| error_description | string | Human-readable description of the error. |
{
"error" : "invalid_grant",
"error_description" : "Invalid username or password"
}
curl -X POST "https://app.timebutler.com/api/v2/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d 'grant_type=password&username=user%40example.com&password=s3cr3t&client_id=public'
curl -X POST "https://app.timebutler.com/api/v2/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d 'grant_type=refresh_token&refresh_token=550e8400-e29b-41d4-a716-446655440000&client_id=public'
curl -X POST "https://app.timebutler.com/api/v2/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d 'grant_type=mfa_totp&mfa_token=mfa-a1b2c3d4e5f6&totp_code=123456&client_id=public'
Vacation, sick-leave and other time-off requests. Employees submit and manage their own requests (`/my`, `POST`, `PUT /{id}`, `DELETE /{id}`); managers and admins see their team's open requests (`/team`, `/pending-count`) and approve or reject them (`POST /{id}/approve`, `POST /{id}/reject`). All endpoints require a bearer token.
/absence-requests/{id}/approveApprove a pending absence request
Records the caller's approval on a request in the `pending` state. If the employee has multiple managers, the request only transitions to `approved` once all managers have approved (or if an admin approves). Callers must be an admin or the direct manager of the request's owner.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Internal ID of the absence request to approve. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request. |
| type | string | Absence type code (3 characters), e.g. `"URL"` for vacation. |
| startDate | string | First day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | Last day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans, calculated according to the employee's working-days schedule. |
| status | string | Current status of the request. One of `pending` (awaiting manager approval), `approved`, or `rejected`. Possible values: pending approved rejected |
| halfDay | string | Half-day indicator. `"morning"` or `"afternoon"` for half-day requests; `null` for full-day absences. Possible values: morning afternoon |
| substitutePending | boolean | Whether the substitute employee's confirmation is still pending. `null` if no substitute was set. |
| medicalCertificateProvided | boolean | Whether a medical certificate has been uploaded for this absence. Only present for absence types that require a sick note; `null` otherwise. |
| employeeName | string | Display name of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
| employeeId | string | Internal ID of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
{
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
}
curl -X POST "https://app.timebutler.com/api/v2/absence-requests/{id}/approve" \
-H "Authorization: Bearer <token>"
/absence-requestsList the caller's own absence requests (alias)
Convenience alias that returns the same result as `GET /my`. Prefer `/my` in new integrations — this path exists for backwards compatibility.
[ {
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
} ]
curl -X GET "https://app.timebutler.com/api/v2/absence-requests" \ -H "Authorization: Bearer <token>"
/absence-requestsCreate a new absence request
Submits a new absence or vacation request for the caller. The resulting status depends on the absence type's configuration: types that require manager approval start as `pending`, otherwise they go straight to `approved`. Dates are ISO-8601 (`YYYY-MM-DD`). For half-day requests set `halfDay` to `morning` or `afternoon` and use the same value for `startDate` and `endDate`.
Fields of the new absence request.
| Name | Type | Description |
|---|---|---|
| absenceTypeIdrequired | string | Absence type code (3 characters), e.g. `"URL"` for vacation. Must match an active type from `GET /absence-types`. |
| startDaterequired | string | First day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| endDaterequired | string | Last day of the absence in ISO-8601 format (`YYYY-MM-DD`). Must be on or after `startDate`. For half-day requests must equal `startDate`. |
| halfDay | string | Set to `"morning"` or `"afternoon"` to request a single half-day. When set, `startDate` and `endDate` must be the same day. Omit or send `null` for a full-day absence. Possible values: morning afternoon |
| comments | string | Optional free-text note visible to the employee's managers. |
| substituteEmployeeId | string | Employee ID of the designated substitute. Must belong to the same company. Omit or send `null` if no substitute is needed. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request. |
| type | string | Absence type code (3 characters), e.g. `"URL"` for vacation. |
| startDate | string | First day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | Last day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans, calculated according to the employee's working-days schedule. |
| status | string | Current status of the request. One of `pending` (awaiting manager approval), `approved`, or `rejected`. Possible values: pending approved rejected |
| halfDay | string | Half-day indicator. `"morning"` or `"afternoon"` for half-day requests; `null` for full-day absences. Possible values: morning afternoon |
| substitutePending | boolean | Whether the substitute employee's confirmation is still pending. `null` if no substitute was set. |
| medicalCertificateProvided | boolean | Whether a medical certificate has been uploaded for this absence. Only present for absence types that require a sick note; `null` otherwise. |
| employeeName | string | Display name of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
| employeeId | string | Internal ID of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
{
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
}
curl -X POST "https://app.timebutler.com/api/v2/absence-requests" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"absenceTypeId":"URL","startDate":"2025-08-01","endDate":"2025-08-05","halfDay":"morning","comments":"Holiday trip","substituteEmployeeId":"42"}'
/absence-requests/{id}Update an existing absence request
Updates a request that is still in the `pending` or `edit` state. Only the fields provided in the request body are changed; `null` fields are left as they were. Non-admins can only update their own requests. Requests that have already been approved or rejected cannot be updated and will return `409 Conflict`.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Internal ID of the absence request to update. Matches `id` from `GET /my` or `GET /team`. |
Fields to update. Omit a field (send `null`) to keep the existing value.
| Name | Type | Description |
|---|---|---|
| absenceTypeId | string | New absence type code (3 characters). Send `null` to keep the existing type. |
| startDate | string | New start date in ISO-8601 format (`YYYY-MM-DD`). Send `null` to keep the existing value. |
| endDate | string | New end date in ISO-8601 format (`YYYY-MM-DD`). Must be on or after `startDate`. Send `null` to keep the existing value. |
| halfDay | string | New half-day setting. `"morning"` or `"afternoon"` to switch to a half-day; empty string `""` to remove half-day and make it a full day; `null` to keep the existing value. Possible values: morning afternoon |
| comments | string | New free-text comment. Send `null` to keep the existing comment; send an empty string to clear it. |
| substituteEmployeeId | string | New substitute employee ID. Send `null` to keep the existing substitute; send `"0"` or an empty string to remove the substitute. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request. |
| type | string | Absence type code (3 characters), e.g. `"URL"` for vacation. |
| startDate | string | First day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | Last day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans, calculated according to the employee's working-days schedule. |
| status | string | Current status of the request. One of `pending` (awaiting manager approval), `approved`, or `rejected`. Possible values: pending approved rejected |
| halfDay | string | Half-day indicator. `"morning"` or `"afternoon"` for half-day requests; `null` for full-day absences. Possible values: morning afternoon |
| substitutePending | boolean | Whether the substitute employee's confirmation is still pending. `null` if no substitute was set. |
| medicalCertificateProvided | boolean | Whether a medical certificate has been uploaded for this absence. Only present for absence types that require a sick note; `null` otherwise. |
| employeeName | string | Display name of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
| employeeId | string | Internal ID of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
{
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
}
curl -X PUT "https://app.timebutler.com/api/v2/absence-requests/{id}" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"absenceTypeId":"URL","startDate":"2025-08-01","endDate":"2025-08-05","halfDay":"morning","comments":"Rescheduled trip","substituteEmployeeId":"42"}'
/absence-requests/{id}Delete an absence request or send a cancellation request
Behaviour depends on the current state of the request and the caller's rights: if the caller may delete the request outright it is removed and the `result` field of the response is `"deleted"`. Otherwise a cancellation request is created that the employee's managers then have to approve, and the response `result` is `"cancellation_requested"`. A reason may be required by the company's configuration when only cancellation is possible.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Internal ID of the absence request to delete or cancel. |
Optional body with a free-text `reason`. Required for cancellation requests when the company's configuration forces a reason.
| Name | Type | Description |
|---|---|---|
| reason | string | Optional free-text reason for the cancellation. Required when the company's configuration mandates a reason for cancellation requests. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the affected record. |
| result | string | Outcome of the operation. `"deleted"` if the record was removed outright; `"cancellation_requested"` if a cancellation request was created instead; `"deletion_requested"` if a deletion request was created (for time entries that require approval). Possible values: deleted cancellation_requested deletion_requested |
{
"id" : "12345",
"result" : "deleted"
}
curl -X DELETE "https://app.timebutler.com/api/v2/absence-requests/{id}" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"reason":"Plans changed"}'
/absence-requests/myList the caller's own absence requests
Returns every absence and vacation request belonging to the caller, in any state (pending, approved, rejected, done). Does not include requests the caller manages for their direct reports — for those see `/team`.
[ {
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
} ]
curl -X GET "https://app.timebutler.com/api/v2/absence-requests/my" \ -H "Authorization: Bearer <token>"
/absence-requests/pending-countPending request counts for the caller's team
Returns two counts for the caller's direct reports: open absence requests awaiting the caller's approval, and open cancellation requests. Used to show notification badges on the manager dashboard. Returns zeros when the caller has no direct reports.
| Name | Type | Description |
|---|---|---|
| numberOfAbsenceRequests | integer(int32) | Number of absence requests in the caller's team that are waiting for the caller's approval. |
| numberOfAbsenceRequestCancellations | integer(int32) | Number of cancellation requests in the caller's team that are waiting for approval. |
{
"numberOfAbsenceRequests" : 3,
"numberOfAbsenceRequestCancellations" : 1
}
curl -X GET "https://app.timebutler.com/api/v2/absence-requests/pending-count" \ -H "Authorization: Bearer <token>"
/absence-requests/teamList absence requests of the caller's direct reports
Returns every absence request belonging to employees the caller manages (admins see all company users), across all states. Each entry includes the employee's display name and ID so the result can be rendered as a team calendar or review list. Empty array if the caller has no direct reports.
[ {
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
} ]
curl -X GET "https://app.timebutler.com/api/v2/absence-requests/team" \ -H "Authorization: Bearer <token>"
/absence-requests/{id}/rejectReject a pending absence request
Marks a pending absence request as rejected. An optional rejection reason may be passed in the body — it is stored and shown to the requesting employee. Callers must be an admin or the direct manager of the request's owner.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Internal ID of the absence request to reject. |
Optional body containing a `reason` string shown to the employee.
| Name | Type | Description |
|---|---|---|
| reason | string | Optional free-text reason for the rejection. Stored on the request and shown to the employee. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request. |
| type | string | Absence type code (3 characters), e.g. `"URL"` for vacation. |
| startDate | string | First day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | Last day of the absence in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans, calculated according to the employee's working-days schedule. |
| status | string | Current status of the request. One of `pending` (awaiting manager approval), `approved`, or `rejected`. Possible values: pending approved rejected |
| halfDay | string | Half-day indicator. `"morning"` or `"afternoon"` for half-day requests; `null` for full-day absences. Possible values: morning afternoon |
| substitutePending | boolean | Whether the substitute employee's confirmation is still pending. `null` if no substitute was set. |
| medicalCertificateProvided | boolean | Whether a medical certificate has been uploaded for this absence. Only present for absence types that require a sick note; `null` otherwise. |
| employeeName | string | Display name of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
| employeeId | string | Internal ID of the employee who submitted the request. Only present in responses from `GET /team`; `null` in `GET /my` responses. |
{
"id" : "12345",
"type" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"halfDay" : "morning",
"substitutePending" : false,
"medicalCertificateProvided" : false,
"employeeName" : "Maria Müller",
"employeeId" : "42"
}
curl -X POST "https://app.timebutler.com/api/v2/absence-requests/{id}/reject" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"reason":"Insufficient staffing during that period"}'
Lookup list of absence types configured for the company (vacation, sick leave, etc.). Used to populate dropdowns when creating an absence request.
/absence-typesList absence types
Returns all active absence types the authenticated user is allowed to submit.
[ {
"id" : "URL",
"name" : "Urlaub",
"needsApproval" : true,
"requiresMedicalCertificate" : false
} ]
curl -X GET "https://app.timebutler.com/api/v2/absence-types" \ -H "Authorization: Bearer <token>"
Requests by employees to cancel (delete) an already-approved absence. Managers and admins see pending cancellation requests for their team and can approve or reject them.
/cancellation-requests/{id}/approveApprove a cancellation request
Approves the pending cancellation request for the given absence. The absence is deleted and notification emails are sent. Requires `MANAGER` or `ADMIN` role.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Absence ID. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request being cancelled. |
| employeeId | string | Internal ID of the employee who submitted the original absence request. |
| employeeName | string | Display name of the employee who submitted the original absence request. |
| absenceType | string | Absence type code (3 characters) of the request being cancelled. |
| startDate | string | Start date of the absence being cancelled, in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | End date of the absence being cancelled, in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans. |
| status | string | Current status of the cancellation request. One of `pending` (awaiting approval) or `approved`. Possible values: pending approved |
| cancelComments | string | Optional free-text reason provided by the employee when requesting the cancellation. |
{
"id" : "12345",
"employeeId" : "42",
"employeeName" : "Maria Müller",
"absenceType" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"cancelComments" : "Plans changed"
}
curl -X POST "https://app.timebutler.com/api/v2/cancellation-requests/{id}/approve" \
-H "Authorization: Bearer <token>"
/cancellation-requestsList pending cancellation requests
Returns all pending cancellation requests visible to the authenticated manager or admin. Requires `MANAGER` or `ADMIN` role.
[ {
"id" : "12345",
"employeeId" : "42",
"employeeName" : "Maria Müller",
"absenceType" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"cancelComments" : "Plans changed"
} ]
curl -X GET "https://app.timebutler.com/api/v2/cancellation-requests" \ -H "Authorization: Bearer <token>"
/cancellation-requests/pending-countGet pending cancellation count
Returns the number of cancellation requests waiting for a manager or admin decision. Requires `MANAGER` or `ADMIN` role.
| Name | Type | Description |
|---|---|---|
| numberOfCancellationRequests | integer(int32) | Number of cancellation requests in the caller's team that are waiting for approval. |
{
"numberOfCancellationRequests" : 2
}
curl -X GET "https://app.timebutler.com/api/v2/cancellation-requests/pending-count" \ -H "Authorization: Bearer <token>"
/cancellation-requests/{id}/rejectReject a cancellation request
Rejects the pending cancellation request. The absence is kept; the employee is notified by email. Requires `MANAGER` or `ADMIN` role.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Absence ID. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request being cancelled. |
| employeeId | string | Internal ID of the employee who submitted the original absence request. |
| employeeName | string | Display name of the employee who submitted the original absence request. |
| absenceType | string | Absence type code (3 characters) of the request being cancelled. |
| startDate | string | Start date of the absence being cancelled, in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | End date of the absence being cancelled, in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans. |
| status | string | Current status of the cancellation request. One of `pending` (awaiting approval) or `approved`. Possible values: pending approved |
| cancelComments | string | Optional free-text reason provided by the employee when requesting the cancellation. |
{
"id" : "12345",
"employeeId" : "42",
"employeeName" : "Maria Müller",
"absenceType" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending",
"cancelComments" : "Plans changed"
}
curl -X POST "https://app.timebutler.com/api/v2/cancellation-requests/{id}/reject" \
-H "Authorization: Bearer <token>"
Lookup list of time-tracking categories for the company. Used when creating or stopping a clock entry.
/categoriesList categories
Returns all active categories along with the user's default category and whether a category is required when saving a time entry.
| Name | Type | Description |
|---|---|---|
| categories | CategoryDto[] | List of categories available to the authenticated user's company. |
| id | string | Internal ID of the category, used when submitting a time entry. |
| name | string | Human-readable name of the category. |
| defaultCategoryId | string | ID of the category pre-selected by default when creating a time entry. `null` if no default is configured. |
| isCategoryMandatory | boolean | Whether the employee must select a category when creating a time entry. |
{
"categories" : [ {
"id" : "7",
"name" : "Internal project"
} ],
"defaultCategoryId" : "7",
"isCategoryMandatory" : false
}
curl -X GET "https://app.timebutler.com/api/v2/categories" \ -H "Authorization: Bearer <token>"
Lookup list of time-tracking projects for the company. Favorites are listed first. Used when creating a clock entry or time-tracking record.
/projectsList projects
Returns all active projects. The user's favourites appear first, followed by all other active projects. Also returns the user's default project and whether a project is required.
| Name | Type | Description |
|---|---|---|
| projects | ProjectDto[] | List of projects available to the authenticated user's company. |
| id | string | Internal ID of the project, used when submitting a time entry. |
| name | string | Human-readable name of the project. |
| isFavorite | boolean | Whether this project is marked as a favourite by the authenticated user. |
| defaultProjectId | string | ID of the project pre-selected by default when creating a time entry. `null` if no default is configured. |
| isProjectMandatory | boolean | Whether the employee must select a project when creating a time entry. |
{
"projects" : [ {
"id" : "5",
"name" : "Website Relaunch",
"isFavorite" : true
} ],
"defaultProjectId" : "5",
"isProjectMandatory" : true
}
curl -X GET "https://app.timebutler.com/api/v2/projects" \ -H "Authorization: Bearer <token>"
Lookup list of employees that may be selected as a substitute when submitting an absence request.
/substitute-employeesList substitute employees
Returns all active employees in the company that may serve as a substitute for the authenticated user. The authenticated user is excluded from the list.
[ {
"id" : "42",
"name" : "Thomas Schmidt",
"department" : "Engineering"
} ]
curl -X GET "https://app.timebutler.com/api/v2/substitute-employees" \ -H "Authorization: Bearer <token>"
Requests sent to the authenticated user asking them to act as a substitute during a colleague's absence. The user can accept or reject each request.
/substitute-requests/{id}/acceptAccept a substitute request
Accepts the substitute request for the given absence. Only the designated substitute may call this endpoint.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Absence ID. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request for which the substitute was requested. |
| employeeId | string | Internal ID of the employee who is absent and needs a substitute. |
| employeeName | string | Display name of the absent employee. |
| absenceType | string | Absence type code (3 characters) of the absence for which this substitute was requested. |
| startDate | string | Start date of the absence, in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | End date of the absence, in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans. |
| status | string | Current status of the substitute confirmation. One of `pending` (awaiting the substitute's confirmation) or `confirmed`. Possible values: pending confirmed |
{
"id" : "12345",
"employeeId" : "7",
"employeeName" : "Anna Bauer",
"absenceType" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending"
}
curl -X POST "https://app.timebutler.com/api/v2/substitute-requests/{id}/accept" \
-H "Authorization: Bearer <token>"
/substitute-requests/pending-countGet pending substitute request count
Returns the number of substitute requests that are still waiting for the authenticated user's response.
| Name | Type | Description |
|---|---|---|
| numberOfSubstituteRequests | integer(int32) | Number of substitute requests awaiting the caller's confirmation. |
{
"numberOfSubstituteRequests" : 1
}
curl -X GET "https://app.timebutler.com/api/v2/substitute-requests/pending-count" \ -H "Authorization: Bearer <token>"
/substitute-requestsList substitute requests
Returns all substitute requests directed at the authenticated user, regardless of their status (pending, accepted, rejected).
[ {
"id" : "12345",
"employeeId" : "7",
"employeeName" : "Anna Bauer",
"absenceType" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending"
} ]
curl -X GET "https://app.timebutler.com/api/v2/substitute-requests" \ -H "Authorization: Bearer <token>"
/substitute-requests/{id}/rejectReject a substitute request
Rejects the substitute request for the given absence. Only the designated substitute may call this endpoint.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Absence ID. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the absence request for which the substitute was requested. |
| employeeId | string | Internal ID of the employee who is absent and needs a substitute. |
| employeeName | string | Display name of the absent employee. |
| absenceType | string | Absence type code (3 characters) of the absence for which this substitute was requested. |
| startDate | string | Start date of the absence, in ISO-8601 format (`YYYY-MM-DD`). |
| endDate | string | End date of the absence, in ISO-8601 format (`YYYY-MM-DD`). |
| days | number(double) | Number of working days the absence spans. |
| status | string | Current status of the substitute confirmation. One of `pending` (awaiting the substitute's confirmation) or `confirmed`. Possible values: pending confirmed |
{
"id" : "12345",
"employeeId" : "7",
"employeeName" : "Anna Bauer",
"absenceType" : "URL",
"startDate" : "2025-08-01",
"endDate" : "2025-08-05",
"days" : 4.0,
"status" : "pending"
}
curl -X POST "https://app.timebutler.com/api/v2/substitute-requests/{id}/reject" \
-H "Authorization: Bearer <token>"
Real-time time clock. Start, pause, resume, stop, or cancel the running clock for the authenticated user. Business-trip mode is also controlled here.
/time-clock/business-trip-endEnd a business trip
Marks the end of an active business trip on the current clock. Returns 409 if no business trip is currently active.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/business-trip-end" \ -H "Authorization: Bearer <token>"
/time-clock/business-trip-startStart a business trip
Marks the start of a business trip on the currently running or paused clock. Returns 400 if business trips are not enabled for this company; returns 409 if the clock is not active or a business trip is already in progress.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/business-trip-start" \ -H "Authorization: Bearer <token>"
/time-clock/cancelCancel the time clock
Discards the current clock session without saving a time entry. Returns 409 if the clock is already `idle`.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/cancel" \ -H "Authorization: Bearer <token>"
/time-clock/statusGet time clock status
Returns the current state of the time clock: `idle`, `running`, `paused`, or `waiting`. Also returns elapsed time, pause time, and business-trip flag.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X GET "https://app.timebutler.com/api/v2/time-clock/status" \ -H "Authorization: Bearer <token>"
/time-clock/pausePause the time clock
Pauses a running time clock. Returns 409 if the clock is not in `running` state.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/pause" \ -H "Authorization: Bearer <token>"
/time-clock/resumeResume the time clock
Resumes a paused time clock. Returns 409 if the clock is not in `paused` state.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/resume" \ -H "Authorization: Bearer <token>"
/time-clock/startStart the time clock
Starts the time clock for the authenticated user. Returns 409 if the clock is already running. The clock may enter `waiting` state if a minimum start interval is configured.
| Name | Type | Description |
|---|---|---|
| status | string | Current state of the time clock. One of `idle` (not running), `running` (clocked in), `paused`, or `waiting` (started but held until a minimum interval passes). Possible values: idle running paused waiting |
| startTimestamp | integer(int64) | Unix timestamp in milliseconds when the current clock-in session started. `null` when `status` is `idle`. |
| pauseTimestamp | integer(int64) | Unix timestamp in milliseconds when the current pause started. `null` if the clock is not paused. |
| workTimeElapsedSeconds | integer(int32) | Total working time elapsed in the current session, in seconds (excludes breaks). |
| breakElapsedSeconds | integer(int32) | Duration of the current ongoing break, in seconds. `0` if the clock is not paused. |
| accumulatedBreakSeconds | integer(int32) | Total accumulated break time in the current session, in seconds (including any completed breaks). |
| waitSeconds | integer(int32) | Minimum number of seconds remaining before the employee is allowed to clock out, based on company policy. `null` if there is no minimum. |
| isBusinessTripActive | boolean | Whether a business trip is currently active for this session. `false` when no business trip is active or the feature is not enabled. |
{
"status" : "running",
"startTimestamp" : 1753700400000,
"pauseTimestamp" : 1753714800000,
"workTimeElapsedSeconds" : 14400,
"breakElapsedSeconds" : 0,
"accumulatedBreakSeconds" : 1800,
"waitSeconds" : 0,
"isBusinessTripActive" : false
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/start" \ -H "Authorization: Bearer <token>"
/time-clock/stopStop and save the time clock
Stops the running or paused clock and saves the resulting time entry. An optional project ID and remarks can be provided. If the clock was in `waiting` state it is discarded without saving and 204 is returned. Returns 409 if the total duration is too short (< 1 minute) or if a duplicate entry is detected.
Optional project ID, category ID, and remarks for the saved entry.
| Name | Type | Description |
|---|---|---|
| projectId | integer(int32) | ID of the project to assign the completed session to. Send `0` if no project assignment is needed. |
| categoryId | integer(int32) | ID of the category to assign the completed session to. Send `0` if no category assignment is needed. |
| remarks | string | Optional free-text note for the completed time entry. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the time entry created when the clock was stopped. |
| workedMinutes | integer(int32) | Net working time recorded for the session, in minutes (total duration minus breaks). |
| breakMinutes | integer(int32) | Total break time recorded for the session, in minutes. |
{
"id" : "98765",
"workedMinutes" : 480,
"breakMinutes" : 30
}
curl -X POST "https://app.timebutler.com/api/v2/time-clock/stop" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"projectId":5,"categoryId":7,"remarks":"Code review"}'
Manage individual time-tracking entries. Managers and admins can see how many entries are pending approval; any user can delete their own entries (subject to month-lock and approval-workflow rules).
/time-entries/{id}Delete a time entry
Deletes the specified time entry. If the company's time-tracking settings require manager approval for deletions, a deletion request is submitted instead of an immediate delete. The response field `result` is either `deleted` or `deletion_requested`.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Time entry ID. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the affected record. |
| result | string | Outcome of the operation. `"deleted"` if the record was removed outright; `"cancellation_requested"` if a cancellation request was created instead; `"deletion_requested"` if a deletion request was created (for time entries that require approval). Possible values: deleted cancellation_requested deletion_requested |
{
"id" : "12345",
"result" : "deleted"
}
curl -X DELETE "https://app.timebutler.com/api/v2/time-entries/{id}" \
-H "Authorization: Bearer <token>"
/time-entries/pending-countGet pending time-entry count
Returns the number of time entries in the manager's team that are awaiting approval. Requires `MANAGER` or `ADMIN` role.
| Name | Type | Description |
|---|---|---|
| numberOfTimeEntries | integer(int32) | Number of time entries in the caller's team that are waiting for approval. |
{
"numberOfTimeEntries" : 5
}
curl -X GET "https://app.timebutler.com/api/v2/time-entries/pending-count" \ -H "Authorization: Bearer <token>"
Pending change or deletion requests for time entries that require manager or admin approval. Managers and admins can list, approve, and reject these requests.
/time-entry-requests/{id}/approveApprove a time-entry request
Approves the pending change or deletion request for the given time entry. For deletion requests the entry is removed; for change requests the entry is updated to the proposed values. Requires `MANAGER` or `ADMIN` role.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Time entry ID. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the time entry. |
| employeeId | string | Internal ID of the employee who submitted the time entry. Only present in team/manager views. |
| employeeName | string | Display name of the employee who submitted the time entry. Only present in team/manager views. |
| date | string | Date of the time entry in ISO-8601 format (`YYYY-MM-DD`). |
| startTime | string | Clock-in time in `HH:mm` format. |
| endTime | string | Clock-out time in `HH:mm` format. |
| workedMinutes | integer(int32) | Net working time for this entry, in minutes (total duration minus breaks). |
| breakMinutes | integer(int32) | Total break time for this entry, in minutes. |
| project | string | Name of the project assigned to this entry. `null` if no project was assigned. |
| category | string | Name of the category assigned to this entry. `null` if no category was assigned. |
| remarks | string | Free-text note attached to this entry. `null` if no remark was entered. |
| requestType | string | Type of request that produced this entry. One of `manual` (entered by hand) or `clock` (created by stopping the time clock). Possible values: manual clock |
| status | string | Approval status of this time entry. One of `pending` (awaiting manager approval) or `approved`. Possible values: pending approved |
{
"id" : "98765",
"employeeId" : "42",
"employeeName" : "Maria Müller",
"date" : "2025-07-28",
"startTime" : "08:00",
"endTime" : "17:00",
"workedMinutes" : 480,
"breakMinutes" : 60,
"project" : "Website Relaunch",
"category" : "Internal project",
"remarks" : "Sprint planning",
"requestType" : "manual",
"status" : "pending"
}
curl -X POST "https://app.timebutler.com/api/v2/time-entry-requests/{id}/approve" \
-H "Authorization: Bearer <token>"
/time-entry-requestsList pending time-entry requests
Returns all time-entry change/deletion requests in the manager's team that are waiting for approval. Requires `MANAGER` or `ADMIN` role. Returns an empty list if time tracking is not active or the caller is a manager in an admin-only-approval company.
[ {
"id" : "98765",
"employeeId" : "42",
"employeeName" : "Maria Müller",
"date" : "2025-07-28",
"startTime" : "08:00",
"endTime" : "17:00",
"workedMinutes" : 480,
"breakMinutes" : 60,
"project" : "Website Relaunch",
"category" : "Internal project",
"remarks" : "Sprint planning",
"requestType" : "manual",
"status" : "pending"
} ]
curl -X GET "https://app.timebutler.com/api/v2/time-entry-requests" \ -H "Authorization: Bearer <token>"
/time-entry-requests/{id}/rejectReject a time-entry request
Rejects the pending change or deletion request for the given time entry. An optional rejection reason can be included in the request body. The employee is notified by email. Requires `MANAGER` or `ADMIN` role.
| Name | Type | Description |
|---|---|---|
| idrequired | integer(int32) | Time entry ID. |
Optional rejection reason.
| Name | Type | Description |
|---|---|---|
| reason | string | Optional free-text reason for the rejection. Stored on the request and shown to the employee. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the time entry. |
| employeeId | string | Internal ID of the employee who submitted the time entry. Only present in team/manager views. |
| employeeName | string | Display name of the employee who submitted the time entry. Only present in team/manager views. |
| date | string | Date of the time entry in ISO-8601 format (`YYYY-MM-DD`). |
| startTime | string | Clock-in time in `HH:mm` format. |
| endTime | string | Clock-out time in `HH:mm` format. |
| workedMinutes | integer(int32) | Net working time for this entry, in minutes (total duration minus breaks). |
| breakMinutes | integer(int32) | Total break time for this entry, in minutes. |
| project | string | Name of the project assigned to this entry. `null` if no project was assigned. |
| category | string | Name of the category assigned to this entry. `null` if no category was assigned. |
| remarks | string | Free-text note attached to this entry. `null` if no remark was entered. |
| requestType | string | Type of request that produced this entry. One of `manual` (entered by hand) or `clock` (created by stopping the time clock). Possible values: manual clock |
| status | string | Approval status of this time entry. One of `pending` (awaiting manager approval) or `approved`. Possible values: pending approved |
{
"id" : "98765",
"employeeId" : "42",
"employeeName" : "Maria Müller",
"date" : "2025-07-28",
"startTime" : "08:00",
"endTime" : "17:00",
"workedMinutes" : 480,
"breakMinutes" : 60,
"project" : "Website Relaunch",
"category" : "Internal project",
"remarks" : "Sprint planning",
"requestType" : "manual",
"status" : "pending"
}
curl -X POST "https://app.timebutler.com/api/v2/time-entry-requests/{id}/reject" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"reason":"Insufficient staffing during that period"}'
Today's work and time-off summaries for the authenticated user, plus an endpoint for submitting completed clock entries (start/end timestamps) directly without the real-time time clock.
/time-tracking/clock-entrySubmit a completed clock entry
Creates a time entry from explicit start and end Unix timestamps (milliseconds). Start and end must be on the same calendar day. If the company requires manager approval for new entries, the entry is created with status `pending`; otherwise it is immediately `done`.
Clock entry with start/end timestamps and optional project and remarks.
| Name | Type | Description |
|---|---|---|
| startTimestamprequired | integer(int64) | Start of the work period as a Unix timestamp in milliseconds. |
| endTimestamprequired | integer(int64) | End of the work period as a Unix timestamp in milliseconds. |
| pauseSeconds | integer(int32) | Total break duration within the work period, in seconds. |
| projectId | integer(int32) | ID of the project to assign this entry to. Send `0` if no project assignment is needed. |
| remarks | string | Optional free-text note for this time entry. |
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the created time entry. |
| workedMinutes | integer(int32) | Net working time recorded for this entry, in minutes (total duration minus breaks). |
| breakMinutes | integer(int32) | Total break time recorded for this entry, in minutes. |
{
"id" : "98765",
"workedMinutes" : 480,
"breakMinutes" : 30
}
curl -X POST "https://app.timebutler.com/api/v2/time-tracking/clock-entry" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"startTimestamp":1753700400000,"endTimestamp":1753729200000,"pauseSeconds":1800,"projectId":5,"remarks":"Sprint planning"}'
/time-tracking/time-off-summaryGet time-off summary
Returns the authenticated user's remaining and total vacation days for the current year, plus the number of illness days taken.
| Name | Type | Description |
|---|---|---|
| vacationDaysRemaining | number(double) | Number of vacation days the employee still has available in the current year, after accounting for approved and pending requests. |
| vacationDaysTotal | number(double) | Total vacation day entitlement for the current year. |
| illnessDaysTaken | number(double) | Number of sick-leave days taken in the current year. |
{
"vacationDaysRemaining" : 12.5,
"vacationDaysTotal" : 30.0,
"illnessDaysTaken" : 3.0
}
curl -X GET "https://app.timebutler.com/api/v2/time-tracking/time-off-summary" \ -H "Authorization: Bearer <token>"
/time-tracking/work-summaryGet today's work summary
Returns the authenticated user's work commitment, worked minutes, remaining minutes, completion percentage, and break minutes for today.
| Name | Type | Description |
|---|---|---|
| commitmentMinutes | integer(int32) | Total working time the employee is contractually required to work in the queried period, in minutes. |
| workedMinutes | integer(int32) | Total working time the employee has actually worked in the queried period, in minutes. |
| remainingMinutes | integer(int32) | Remaining working time still to be worked in the queried period, in minutes. Negative values indicate overtime. |
| percentDone | integer(int32) | Percentage of the contractual working time that has been worked so far, rounded to the nearest integer. |
| breakMinutes | integer(int32) | Total break time recorded in the queried period, in minutes. |
{
"commitmentMinutes" : 2400,
"workedMinutes" : 2280,
"remainingMinutes" : 120,
"percentDone" : 95,
"breakMinutes" : 300
}
curl -X GET "https://app.timebutler.com/api/v2/time-tracking/work-summary" \ -H "Authorization: Bearer <token>"
Basic profile information for the authenticated user: name, email, role, department, and avatar URL.
/user/profileGet profile
Returns the authenticated user's display name, email address, role (`USER`, `MANAGER`, `ADMIN`), department, branch office, and avatar URL.
| Name | Type | Description |
|---|---|---|
| id | string | Internal ID of the authenticated user. |
| name | string | Full display name of the user. |
| string | Email address of the user. | |
| role | string | Role of the user within the company. One of `USER`, `MANAGER`, or `ADMIN`. Possible values: USER MANAGER ADMIN |
| department | string | Name of the department the user belongs to. `null` if the company does not use departments. |
| branchOffice | string | Name of the branch office the user is assigned to. `null` if the company does not use branch offices. |
| country | object | Country of the user as configured in their profile. The structure depends on the company's configuration. |
| avatar | string | URL of the user's profile picture. `null` if no avatar has been uploaded. |
| isBusinessTripEnabled | boolean | Whether the business trip feature is enabled for this user. `null` if the feature is not available in the company's plan. |
| isTimeTrackingEnabled | boolean | Whether time tracking is active for the user's company. |
{
"id" : "42",
"name" : "Maria Müller",
"email" : "maria.mueller@example.com",
"role" : "MANAGER",
"department" : "Engineering",
"branchOffice" : "Berlin",
"country" : { },
"avatar" : "/images/avatar/42/abc123.jpg?v=5",
"isBusinessTripEnabled" : true,
"isTimeTrackingEnabled" : true
}
curl -X GET "https://app.timebutler.com/api/v2/user/profile" \ -H "Authorization: Bearer <token>"