Get a user's leave balances
This API method returns the leave balances of a user, calculated the same way as in the Vacation Tracker dashboard, one entry per leave year. Requires `balances:read`. The list is not paginated. - Only active leave types are included, in the order shown in the dashboard. - 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 every amount are unchanged. - For leave types with unlimited days, `baseQuota`, `earned`, `quotaAtYearEnd` and `remaining` are null. - `period=current` returns the leave year that contains today, or the latest leave year when none does; `isCurrent` tells which one it is. Errors: `400 VALIDATION_ERROR` (an invalid `period`) and `404 RESOURCE_NOT_FOUND` (the user does not exist or is outside the key's data reach).
Authorization
bearerAuth balances: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: balances:read
Path Parameters
resource ID.
Query Parameters
current returns only the leave year that contains today (or the latest year if none does), all returns every leave year. Default is current.
"current""current" | "all"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/balances"{
"data": [
{
"userId": "user-63b17e97-d38b-4586-8498-bb4f5d2e2c14",
"yearStart": "2026-01-01",
"yearEnd": "2026-12-31",
"isCurrent": true,
"leaveTypes": [
{
"leaveTypeId": "leaveType-fcc1e5c5-ba93-479d-bd58-8f860ba10615",
"leaveTypeName": "Vacation",
"leavePolicyId": "leavePolicy-2d7c1b9e-5a4f-4c3b-8e1d-7f6a5b4c3d2e",
"accrualType": "NONE",
"unit": "days",
"hasUnlimitedDays": false,
"quotas": {
"baseQuota": {
"days": 20,
"hours": 160,
"isNegative": false
},
"rolloverFromPreviousYear": {
"days": 3,
"hours": 24,
"isNegative": false
},
"seniorityEntitlement": {
"days": 0,
"hours": 0,
"isNegative": false
},
"entitlementByRole": {
"days": 0,
"hours": 0,
"isNegative": false
},
"toil": {
"days": 1,
"hours": 8,
"isNegative": false
},
"toilLapsed": {
"days": 0,
"hours": 0,
"isNegative": false
},
"earned": {
"days": 21,
"hours": 168,
"isNegative": false
},
"quotaAtYearEnd": {
"days": 24,
"hours": 192,
"isNegative": false
},
"expired": {
"days": 0,
"hours": 0,
"isNegative": false
},
"used": {
"days": 8,
"hours": 64,
"isNegative": false
},
"scheduled": {
"days": 5,
"hours": 40,
"isNegative": false
},
"pending": {
"days": 0,
"hours": 0,
"isNegative": false
},
"remaining": {
"days": 11,
"hours": 88,
"isNegative": 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.ioUpdate a user's profile
This API method changes a user's profile. Requires `users:write`. It waits for the change and returns the user with `200`, or `202 Accepted` with an operation to poll. Send only the fields you want to change; at least one field is required. This method merges your changes with the user's current profile, so fields you do not send are left untouched. Send `null` for `endDate`, `employeeId` or `birthday` to clear it. Who can change what: - `name`, `firstName`, `lastName`, `birthday` and `locale` can be changed by the user themselves, or by an admin or a location admin who manages the user. - `email`, `startDate`, `endDate`, `employeeId`, `isAdmin` and `isNameLocked` require the key owner (or the `X-On-Behalf-Of` user) to be an admin, or a location admin who manages the user. Otherwise the request fails with `403 FORBIDDEN`. - A location admin cannot grant or remove Admin: sending `isAdmin` as a location admin fails with `403 FORBIDDEN`. - When the user's name is locked (`isNameLocked: true`), a name change is ignored unless the same request also sends `isNameLocked: true`. **Warning:** setting `isAdmin` to `false` on a user revokes that user's API keys and webhooks within about 60 seconds. If you demote the key owner, the key you are using is revoked too; the call itself still completes. Location, department, Location Admin role and work week are not profile fields; change them with `PUT /v2/users/{id}/location`, `PUT /v2/users/{id}/department`, `PUT /v2/users/{id}/location-admin` and `PUT /v2/users/{id}/work-week`. Errors: `400 VALIDATION_ERROR` (`details.fields`), `403 ON_BEHALF_OF_NOT_ALLOWED`, `403 FORBIDDEN` (the acting user may not change these fields), `404 RESOURCE_NOT_FOUND` (the user does not exist or is outside the key's data reach), `409 EMAIL_ALREADY_EXISTS` (the new email is already used by another user), `409 LAST_ADMIN_CANNOT_BE_REMOVED` (`isAdmin: false` for the company's only admin), `422 PLAN_LIMIT_REACHED` (`isAdmin: true` beyond the plan's admin limit), and the `Idempotency-Key` codes.
List a user's labels
This API method returns the labels assigned to a user. Requires `labels:read`. Labels are company-wide, so this works for any user of the company, whatever the key's data reach. The list is not paginated. Errors: `404 RESOURCE_NOT_FOUND` (the user does not exist).