Vacation Tracker Docs
REST API v2

Authentication and API keys

Create scoped v2 API keys, and learn how the role ceiling, expiry, rotation and revocation work.

Every v2 request needs an API key in the Authorization header, as a bearer token. v2 keys start with vt_live_:

curl "https://api.vacationtracker.io/v2/leaves?startDate=2026-10-01&endDate=2026-10-31" \
  -H "Authorization: Bearer vt_live_..."

A missing or unknown key returns 401 UNAUTHORIZED. A revoked or expired key returns 403 KEY_REVOKED or 403 KEY_EXPIRED. See Errors.

v1 keys (sent in x-api-key) do not work on v2. Create a v2 key instead. See Migrating from v1.

Creating a key

In the dashboard, go to Add-ons → Open API and create a key. Only administrators can create keys today.

  1. Key name. Up to 64 letters, numbers, spaces, _, . or -, unique in your workspace. Only administrators see it, in the list of keys and in company logs.
  2. Integration name (optional). Same characters, up to 64. Everyone sees this name: a change made through the key is shown as "Name (through HR_BOT)" in the leave timeline, notifications and company logs, so choose one your colleagues recognize. Without it, changes show only the person's name, and company logs still show the key and its owner.
  3. What you plan to build (optional). A short description that helps us improve the API.
  4. Permissions. Start from a template (Read only, Leave management, Workspace setup, or Custom), then set each capability to No access, Read or Read & write. Read & write includes read, and also allows deleting.
  5. Sensitive actions. Approving and denying requests, and acting on behalf of other users, are separate checkboxes. Turn them on only when the integration needs them.
  6. Expiration. See Expiration.

The secret is shown once, right after you create the key. Store it in a secret manager. Vacation Tracker keeps only a hash, so a lost secret cannot be recovered: rotate the key to get a new one.

You can change the name, permissions and expiration of an active key later, within your role ceiling.

Scopes

Each capability has a <capability>:read scope and a <capability>:write scope. Write implies read.

CapabilityScopesCovers
leavesleaves:read, leaves:writeLeave requests
toiltoil:read, toil:writeTime off in lieu requests
balancesbalances:readLeave balances (read only)
usersusers:read, users:writeUsers and their settings
locationslocations:read, locations:writeLocations and work weeks
departmentsdepartments:read, departments:writeDepartments
leave-typesleave-types:read, leave-types:writeLeave types
leave-policiesleave-policies:read, leave-policies:writeLeave policies per location
holidaysholidays:read, holidays:writePublic holidays per location
labelslabels:read, labels:writeLabels
automationsautomations:read, automations:writeAutomations
notificationsnotifications:read, notifications:writeNotifications and scheduled reports
webhookswebhooks:read, webhooks:writeWebhooks

Three special scopes cover the sensitive actions. No :write scope implies them:

ScopeGrantsAlso implies
leaves:approveApprove and deny leave and TOIL requests.leaves:read, toil:read
users:act-on-behalfSend requests as another user with X-On-Behalf-Of. See Acting on behalf of users.users:read
leave-types:read-hiddenSee the names of hidden leave types. Without it, a leave type hidden by its leave policy shows as "Hidden Leave Type", like in the dashboard: in the embedded leaveType.name of leaves (with expand=leaveType) and in the leaveTypeName of balances and quotas. leaveTypeId and every amount are kept.leave-types:read

A request that needs a scope the key does not have returns 403 INSUFFICIENT_SCOPE, with the missing scopes in details.requiredScopes.

Role ceiling and data reach

A key never has more access than the person who created it. Scopes above the creator's role cannot be selected, and the key never sees more data than its owner can see.

Owner roleHighest scopesData reach
AdministratorEvery scopeThe whole workspace
Location adminApprover scopes, plus users:write, locations:read/write, departments:read/write, leave-policies:read/write, holidays:write, notifications:read/writeUsers in the locations they manage
ApproverUser scopes, plus leaves:approve, users:act-on-behalf, leave-types:read-hiddenUsers in the departments they approve
Userleaves:read/write, toil:read/write, balances:read, users:read, holidays:read, leave-types:readOnly themselves

Substitute approver assignments do not widen a key. Resources outside the data reach behave as if they do not exist and return 404 RESOURCE_NOT_FOUND.

The data reach depends only on the owner's role, so a key can see less than its owner sees in Vacation Tracker. For example, a user's key reads only their own leaves, even though the user sees colleagues' approved leaves in the calendar. The Visibility add-on does not change the data reach: it is already limited to what the add-on allows.

Expiration

OptionKey stops working
30 days30 days after creation
90 days90 days after creation
1 year (default)1 year after creation
NeverOnly when revoked

An expired key returns KEY_EXPIRED. Create a new key to continue. Choose Never only for integrations you monitor closely.

Rotation

Rotating a key creates a new secret, shown once, and keeps the same key, name and permissions. Choose what happens to the previous secret:

OptionPrevious secret
24 hours (recommended)Keeps working for 24 hours, so you can deploy the new secret without downtime
7 daysKeeps working for 7 days
Stop nowStops working immediately. Use this when a secret has leaked

Only one previous secret works at a time: rotating again ends any overlap still running. Revoked keys cannot be rotated.

Revocation

A revoked key stops working within a minute. Keys are revoked in two ways:

  • Manually, by an administrator in the dashboard, with an optional note.
  • Automatically, when the owner loses privileges the key relies on: they are no longer an administrator, they manage fewer locations or approve fewer departments, or they are deactivated or deleted. The owner's webhooks are revoked in the same way.

A request with a revoked key returns KEY_REVOKED. details.revocationCode says why the key was revoked and details.revocationReason explains it in words:

{
  "error": {
    "code": "KEY_REVOKED",
    "name": "KeyRevoked",
    "description": "The API key has been revoked.",
    "resolution": "See details.revocationReason for why it was revoked, then ask a Vacation Tracker admin to create a new key.",
    "requestId": "...",
    "details": { "revocationCode": "...", "revocationReason": "..." }
  }
}

The same reason is shown on the key in the dashboard. Revoked keys stay in the key list, so administrators can see what happened. Related codes are KEY_OWNER_INACTIVE (the owner was deactivated or deleted) and KEY_SCOPES_EXCEED_ROLE (the owner's role no longer allows the key's scopes).

On this page