Get a user's leave quotas
This API method returns the quota (the base entitlement before rollover, seniority, TOIL and usage) of each leave type in the user's location, for one leave period. Use `GET /v2/users/{id}/balances` for remaining balances. Requires `users:read`. Each quota's `amount` is in that quota's `unit` (`days` or `hours`), as set on the leave policy or on the user's custom quota. `isCustom` is true when the quota was set for this user instead of coming from the location's leave policy. Only active leave types are included. A key without `leave-types:read-hidden` gets `Hidden Leave Type` as `leaveTypeName` for leave types hidden by the policy of the user's location; `leaveTypeId` and `amount` are unchanged. `period` is the only query parameter accepted; any other one fails validation. Errors: `400 VALIDATION_ERROR` (an invalid `period` or an unknown query parameter), `400 QUOTA_PERIOD_NOT_AVAILABLE` (the user has no leave period that contains today, or no next period), and `404 RESOURCE_NOT_FOUND` (the user does not exist or is outside the key's data reach).
Authorization
bearerAuth users:readAPI key sent as Authorization: Bearer vt_live_<secret>. See the Authentication and Scopes sections at the top of this document for how keys are created, which scopes exist and how the key owner's role limits them.
In: header
Scope: users:read
Path Parameters
resource ID.
Query Parameters
current returns the leave period that contains today, next returns the leave period after it. Default is current.
"current""current" | "next"Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v2/users/string/quotas"{
"data": {
"userId": "user-cfe5d39b-f1f0-45aa-85cd-ce93e637a262",
"period": {
"start": "2026-01-01",
"end": "2026-12-31"
},
"quotas": [
{
"leaveTypeId": "leaveType-fcc1e5c5-ba93-479d-bd58-8f860ba10615",
"leaveTypeName": "Vacation",
"unlimited": false,
"amount": 25,
"unit": "days",
"isCustom": true,
"prorate": false,
"ignoreRolloverFromPreviousYear": false
},
{
"leaveTypeId": "leaveType-88681ca1-4a47-4e4d-bc35-ffff86c0f54e",
"leaveTypeName": "Sick leave",
"unlimited": true,
"amount": 0,
"unit": "days",
"isCustom": false,
"prorate": false,
"ignoreRolloverFromPreviousYear": false
}
]
}
}{
"error": {
"code": "VALIDATION_ERROR",
"name": "ValidationError",
"description": "A query parameter, body field or header failed validation.",
"resolution": "Fix the fields listed in details.fields and send the request again.",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"details": {
"fields": [
{
"path": "startDate",
"message": "\"startDate\" is required"
}
]
}
}
}{
"error": {
"code": "UNAUTHORIZED",
"name": "Unauthorized",
"description": "The API key is missing, malformed or not recognized.",
"resolution": "Send a valid API key in the Authorization header as Bearer followed by the full vt_live_ key.",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef"
}
}{
"error": {
"code": "INSUFFICIENT_SCOPE",
"name": "InsufficientScope",
"description": "The API key does not have the scopes this request needs.",
"resolution": "Add the scopes listed in details.requiredScopes to the key in the Vacation Tracker dashboard.",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"details": {
"requiredScopes": [
"leaves:write"
]
}
}
}{
"error": {
"code": "RESOURCE_NOT_FOUND",
"name": "ResourceNotFound",
"description": "The requested resource does not exist or is outside the data this key can access.",
"resolution": "Check the ID of the resource named in details.resource and that the key owner can see it.",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef"
}
}{
"error": {
"code": "RATE_LIMITED",
"name": "RateLimited",
"description": "Too many requests were sent in a short time.",
"resolution": "Wait a few seconds and retry, using the same Idempotency-Key for writes.",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"name": "InternalError",
"description": "Something went wrong on our side.",
"resolution": "Retry later, and if it keeps happening, contact Vacation Tracker support and quote the requestId.",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef"
}
}Need help?
developers@vacationtracker.ioSet a user's custom work week
This API method gives a user their own work week, overriding their location's work week. Requires `users:write`. This is a full replacement, not a merge. Send exactly one of: - `days` (the working days, 0 Sunday .. 6 Saturday, no duplicates), optionally with `workHours` to set the hours worked on each of those days; or - `schedule`, a rotating schedule of one or more `weeks`, each listing `{ day, hours }` per working day, starting from `schedule.startDate`. `workHours` needs `days`; `workHours` and each week of `schedule` list each day at most once. `workHours` and `schedule` are ignored, without an error, when the company's plan does not include custom work hours; only `days` is applied. The key owner (or `X-On-Behalf-Of` user) must be an admin, or a location admin who manages the user. It waits for the change and returns the user with `200`, or `202 Accepted` with an operation to poll. The response does not include the work week. Use `DELETE` to go back to the location's work week. Errors: `400 VALIDATION_ERROR` (`details.fields`, for example both or neither of `days` and `schedule`), `403 ON_BEHALF_OF_NOT_ALLOWED`, `403 FORBIDDEN`, `403 WORK_HOURS_LIMIT_REACHED` (the plan limit on custom work-hour configurations is reached), `404 RESOURCE_NOT_FOUND` (the user does not exist or is outside the key's data reach), and the `Idempotency-Key` codes.
Set a user's quota for a leave type
This API method sets a user's quota for one leave type, the same way as editing it on the user's page in the Vacation Tracker dashboard. Requires `users:write`. This is a full replacement of the quota settings for the chosen period: fields you omit take their defaults. - `amount` is in the company's unit: days, or hours when the company uses hourly accounting. This can differ from the `unit` that `GET /v2/users/{id}/quotas` returns for a leave policy set in the other unit. Up to 365 days or 2920 hours. It is required unless `unlimited` is `true`. - `unlimited: true` gives the user unlimited leave of this type; `amount` is then ignored. - `period` chooses the leave period to change: `current` (default) or `next`. Set `applyToFutureYears: true` to keep this quota in later periods too; by default only the chosen period changes. - `prorate` is allowed only for the user's first leave period (the one containing their start date); sending it for any other period fails with `400 PRORATE_NOT_ALLOWED`. When omitted, the user's prorate setting is left unchanged. The key owner (or `X-On-Behalf-Of` user) must be an admin, or a location admin who manages the user. It waits for the change and returns the user's quotas for the chosen period with `200`, or `202 Accepted` with an operation to poll. Errors: `400 VALIDATION_ERROR` (`details.fields`, including an `amount` above 365 days or 2920 hours), `400 QUOTA_PERIOD_NOT_AVAILABLE` (the requested period does not exist for the user; read `GET /v2/users/{id}/quotas?period=...` to check), `400 PRORATE_NOT_ALLOWED`, `403 ON_BEHALF_OF_NOT_ALLOWED`, `403 FORBIDDEN`, `404 RESOURCE_NOT_FOUND` (the user does not exist or is outside the key's data reach, or the leave type is not active for the user in the chosen period), and the `Idempotency-Key` codes.