Voxbi Cockpit APIs
All endpoints

Create or update an employee's overtime decision (user)

Creates or updates the overtime decision for a single Tempus employee for an overtime calculation period. The endpoint recalculates the period's overtime, derives to_pay / to_increment from the chosen decision (or from an explicit to_pay), and persists the decision via an upsert keyed on tenant, employee and period.

The stored row is fully derived server-side, so the response is the authoritative "after" state:

  • decision_balance — the balance carried into the period, taken from the last LOCKED period's closing balance (never from an unlocked draft).
  • decision_overtime — the period's accrual UP TO TODAY. Days that have not happened yet are not counted, so a decision taken mid-period no longer reports the remaining workdays as undertime.
  • to_pay — what is cashed out, capped at decision_balance + decision_overtime and never negative.
  • to_incrementdecision_overtime - to_pay, i.e. what lands on the balance. Negative when the payout is drawn from the carried-in balance.
  • decision_new_balance — what is left afterwards.

When overtime_calculation_period_id is omitted the active period is resolved from the employee's current contract; if no active contract or no active decision period can be resolved the request is rejected with 422. If a decision for the period has already been processed (locked) it can no longer be changed and the request returns 403. The employee must belong to the requested PBX tenant, otherwise 404 is returned.

HTTP: bearerAuth

User bearer token. Default authentication for customer-facing endpoints. Obtain a token by calling POST /login with your credentials, then send it on every subsequent request as Authorization: Bearer <token>. The token inherits the permissions and PBX scope of the authenticated user.

HTTP Authorization Scheme
bearer
Bearer format
Bearer <token>
pbx_id path · string · uuid *
UUID of the PBX tenant.
employee_id path · string · uuid *
UUID of the Tempus employee.
accept header · string
example: application/json

Request body · required

Request schema
decision*string
What to do with the calculated overtime. `pay` cashes out the whole accrual, `add_to_balance` rolls all of it into the employee's overtime balance, and `custom` means the split is given explicitly through `to_pay`.
enum: pay add_to_balance custom
example: add_to_balance
to_payinteger | string
How much to cash out, as a whole number of seconds (`43200`) or as `"HH:MM"` (`"12:00"`). Overrides `decision`, so an employee can be paid part of the period and bank the rest; the remainder (`decision_overtime - to_pay`) goes to the balance. An explicit `0` means "pay nothing". Rejected with 422 when it exceeds the balance carried in plus the period's accrual. When omitted, the amount follows the `decision` label.
≥ 0
example: 43200
overtime_calculation_period_idstring · uuid
Optional overtime calculation period the decision applies to. Must exist within the requested PBX tenant. When omitted the active period is resolved from the employee's current contract.
example: 550e8400-e29b-41d4-a716-446655440060

Responses

The created or updated overtime decision.
Response schema
dataobject
A single overtime decision recorded against an employee for a given overtime calculation period. A decision captures how an employee's accrued overtime balance is resolved: how much is paid out, converted, reset, or carried forward, together with the resulting new balance. All duration fields (`decision_balance`, `decision_overtime`, `to_pay`, `to_increment`, `to_convert`, `to_reset`, `decision_new_balance`) are expressed as a whole number of seconds. They are returned as raw integer second counts, not as the HHH:MM display strings used in the admin UI. The related calculation period is only present in the response under `overtime_calculation_period` when it has been explicitly loaded by the endpoint (eager loaded); otherwise the field is omitted. **Rows for a period that is still running are computed live.** An employee decides once, part-way through the period, and then keeps working, so the figures stored on the row are a snapshot of that moment and go out of date immediately. On `GET /{pbx_id}/user/{employee_id}/user-overtime-decision`, such a row therefore reports `decision_balance`, `decision_overtime`, `to_increment` and `decision_new_balance` as they stand right now, against the decision the employee made, and `values_live` is true. Settled history — a processed row, or any row whose period has ended — is returned exactly as stored. See `values_live` below.
id*string · uuid
Unique identifier of the overtime decision.
read-only
example: 550e8400-e29b-41d4-a716-446655440000
mxvp_user_id*string · uuid
Identifier of the Pbx (tenant) that owns this decision.
example: 550e8400-e29b-41d4-a716-446655440001
ext_id*string | null
External extension identifier of the employee the decision applies to, resolved from the employee record. Null when the employee has no associated extension.
example: 1042
overtime_calculation_period_id*string | null · uuid
Identifier of the overtime calculation period this decision belongs to. Null when the decision is not linked to a specific period.
example: 550e8400-e29b-41d4-a716-446655440002
decision_type*string
How the decision was created. Defaults to `manual` when not otherwise set. `manual` decisions are entered by an operator, `automatic` decisions are produced by the system.
enum: manual automatic
example: manual
decision*string | null
The chosen resolution applied to the employee's overtime balance for the period (for example whether the overtime is paid out, converted, or reset). Null when no resolution has been selected yet.
example: pay_out
decision_balance*integer · int32
The employee's overtime balance, in seconds, carried into this period: the `decision_new_balance` of the last LOCKED period, or the contract's opening base when nothing has been locked yet. Maps to the model's `old_balance`.
example: 36000
decision_overtime*integer · int32
The overtime accrued during the period, in seconds, that this decision resolves. Counted over COMPLETED days only — the range ends at yesterday midnight, so neither the remaining workdays nor the hours still owed on today are counted as undertime. (A day carries its full shift requirement from the moment it begins, so a day in progress always reads negative.) Negative when the employee genuinely worked less than required over those completed days. Maps to the model's `overtime`. On a running period this is recomputed per request and keeps moving until the period closes; see `values_live`.
example: 7200
to_pay*integer · int32
Amount of overtime, in seconds, to be paid out to the employee. Never negative and never more than `decision_balance + decision_overtime`. This is the employee's own commitment to cash out a given amount, so it is NOT re-derived on a live row even as the accrual grows — it is only clamped down if it would exceed what is available. The growth lands on `to_increment` instead.
example: 3600
to_pay_extra*integer · int32
Additional overtime to pay out, in seconds. Always returned as 0 by this endpoint (reserved for future use).
example: 0
to_increment*integer · int32
Amount of overtime, in seconds, added to the employee's balance: `decision_overtime - to_pay`. Negative when the payout is larger than the period's accrual (the difference is drawn from the carried-in balance), or when the period itself ended in undertime.
example: 0
to_convert*integer · int32
Amount of overtime, in seconds, to be converted (for example into leave or another balance type).
example: 1800
to_reset*integer · int32
Amount of overtime, in seconds, to be reset (discarded) from the balance.
example: 0
decision_new_balance*integer · int32
The resulting overtime balance, in seconds, after applying this decision — what the employee has left once the payout is taken out. Derived by the system as `decision_balance + decision_overtime - to_pay - to_convert - to_reset`. Maps to the model's `new_balance`.
example: 38400
comment*string | null
Optional free-form note explaining or justifying the decision.
example: Carried forward at the employee's request
locked*boolean
Whether the decision has been processed and locked. True once the decision has a processing timestamp, after which it should be treated as final and immutable.
example:
values_live*boolean
Whether the duration fields on this row were computed just now rather than read from the decision snapshot. True only for a row whose period is still running and which has not been processed. Those figures are a moving target — they change as the employee keeps working, and are final only once the period closes and the decision is locked. False for all settled history, where the stored values are returned verbatim.
example:
created*string | null
Timestamp when the decision was created, formatted as `Y-m-d H:i:s` (for example `2024-03-01 08:29:07`). Null when the creation timestamp is not set.
read-only
example: 2024-03-01 08:29:07
overtime_calculation_periodobject
The related overtime calculation period this decision belongs to. Only present when the relation has been eager loaded by the endpoint; otherwise the field is omitted from the response.
idstring · uuid
Unique identifier of the overtime calculation period.
read-only
example: 550e8400-e29b-41d4-a716-446655440002
mxvp_user_idstring · uuid
Identifier of the Pbx (tenant) that owns the period.
example: 550e8400-e29b-41d4-a716-446655440001
company_idstring | null · uuid
Identifier of the Tempus company the period belongs to.
example: 550e8400-e29b-41d4-a716-446655440003
ext_idstring | null
External extension identifier of the employee, falling back to the period's user identifier when the employee has no extension.
example: 1042
startstring | null · date-time
ISO 8601 timestamp marking the start of the calculation period.
example: 2024-03-01T00:00:00Z
endstring | null · date-time
ISO 8601 timestamp marking the end of the calculation period.
example: 2024-03-31T23:59:59Z
lockedboolean
Whether the calculation period is locked and no longer editable.
example:
delete_datestring | null · date-time
ISO 8601 timestamp when the period was soft deleted. Null while the period is active.
Authorization Token Missing. This error is returned when the authorization token is missing.
Response schema
errorstring
Error message
example: Authorization Token is missing
The overtime decision for this period has already been processed and is locked.
Response schema
No response body.
Data Not Found. This error is returned when the requested data is not found.
Response schema
messagearray<string>
[]string
Validation failed: an unknown period, a `to_pay` larger than the employee's available time, or no active contract / decision period to resolve.
Response schema
messagestring
example: You asked to be paid 12:00 but only 07:44 is available (balance carried in plus the overtime accrued this period).
errorsobject
Free-form object
post https://cockpit.voxbi.com/api/v1/{pbx_id}/user/{employee_id}/user-overtime-decision
Base URL
Request sample
curl -X POST 'https://cockpit.voxbi.com/api/v1/{pbx_id}/user/{employee_id}/user-overtime-decision' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  --data '{"decision":"custom","overtime_calculation_period_id":"550e8400-e29b-41d4-a716-446655440060","to_pay":43200}'
const response = await fetch('https://cockpit.voxbi.com/api/v1/{pbx_id}/user/{employee_id}/user-overtime-decision', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${YOUR_TOKEN}`,
  },
  body: JSON.stringify({
    "decision": "custom",
    "overtime_calculation_period_id": "550e8400-e29b-41d4-a716-446655440060",
    "to_pay": 43200
}),
});

const data = await response.json();
console.log(data);
import requests

response = requests.post('https://cockpit.voxbi.com/api/v1/{pbx_id}/user/{employee_id}/user-overtime-decision',
    headers={'Authorization': f'Bearer {YOUR_TOKEN}'},
    json={
    "decision": "custom",
    "overtime_calculation_period_id": "550e8400-e29b-41d4-a716-446655440060",
    "to_pay": 43200
}
)
response.raise_for_status()
data = response.json()
print(data)
<?php
$context = stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\nAuthorization: Bearer YOUR_TOKEN",
        'content' => '{
    \"decision\": \"custom\",
    \"overtime_calculation_period_id\": \"550e8400-e29b-41d4-a716-446655440060\",
    \"to_pay\": 43200
}',
    ],
]);

$response = file_get_contents('https://cockpit.voxbi.com/api/v1/{pbx_id}/user/{employee_id}/user-overtime-decision', false, $context);
$data = json_decode($response, true);
print_r($data);
Sample request
{}
"decision": "custom",
"overtime_calculation_period_id": "550e8400-e29b-41d4-a716-446655440060",
"to_pay": 43200
}
No example for this status.
{}
"error": "Authorization Token is missing"
}
Cache-Control string
example: private, must-revalidate
Connection string
example: keep-alive
Content-Type string
example: application/json
Vary string
example: Origin
X-RateLimit-Limit integer
Max requests allowed in the current rate-limit window.
example: 60
X-RateLimit-Remaining integer
Requests remaining in the current rate-limit window.
example: 57
No example for this status.
{}
"message": []
"Data not found"
]
}
Cache-Control string
example: private, must-revalidate
Connection string
example: keep-alive
Content-Type string
example: application/json
Vary string
example: Origin
X-RateLimit-Limit integer
Max requests allowed in the current rate-limit window.
example: 60
X-RateLimit-Remaining integer
Requests remaining in the current rate-limit window.
example: 57
No example for this status.