API v6
REST API · OpenAPI 3.0

Connect your systems to TimeTac

A RESTful API for reading and writing time tracking, absences, projects and people in a TimeTac account. Every account is isolated: your credentials only ever reach your own company's data.

179Endpoints 74Resources 239Schemas v6API version
Download OpenAPI spec

Quickstart

Three requests from nothing to reading data. Replace {account} with your TimeTac account name — the same name you use to sign in. Type it into Account in the bar above and every example on this page, including the ones in the reference, switches to your account.

  1. Create API credentials

    In TimeTac, create a client ID and client secret for your integration. These identify your application and are scoped to your account only.

  2. Exchange them for an access token

    The API uses OAuth 2.0 client credentials. Tokens are short-lived — read expires_in and refresh before it elapses.

    # returns { "access_token": "...", "token_type": "bearer", "expires_in": 3600 }
    curl -X POST 'https://sandbox-plus-api.timetac.com//auth/oauth2/token' \
      -d 'grant_type=client_credentials' \
      -d 'client_id=YOUR_CLIENT_ID' \
      -d 'client_secret=YOUR_CLIENT_SECRET'
  3. Call an endpoint

    Send the token as a bearer header. Actions are part of the path rather than the HTTP verb, so a read is /timeTrackings/read/.

    curl 'https://sandbox-plus-api.timetac.com//v6/timeTrackings/read/?_limit=10' \
      -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

How requests are shaped

Two conventions carry across every resource. Learn them once and the remaining 179 endpoints behave predictably.

URL structure

The account comes first, then the version, then the resource and its action.

https://{environment}.timetac.com//v6/{resource}/{action}/
{environment}sandbox-plus-api or prod-plus-api
{account}Your TimeTac account name
v6API version
{resource}For example timeTrackings
{action}read, create, update, delete
From v6 onwards the version follows the account directly. The older userapi path segment belongs to v1–v5 only and is not used here.

Response envelope

Every successful response is wrapped; the payload is always the Results array.

{
  "Success": true,
  "NumResults": 2,
  "ResourceName": "timeTrackings",
  "ServerTimeZone": "Europe/Vienna",
  "Results": [
    { "id": 1 },
    { "id": 2 }
  ]
}

Reading, paging and filtering

Every read endpoint accepts the same control parameters. They all start with an underscore, which is what separates them from the resource's own fields.

Paging and sorting

ParameterPurpose
_limitMaximum rows to return. Defaults to 100.
_offsetRows to skip. Combine with _limit to page.
_include_total_num_resultsSet to 1 to add TotalNumResults to the envelope — the full count ignoring _limit, which is what you need to build a pager.
_order_byField name to sort by.
_sort_directionASC or DESC.

Filtering

Any field an endpoint returns can be used as a filter. On its own a field means "equals"; pair it with _op__<field> to choose a different comparison.

# time trackings that started on or after 1 January, newest first
GET /v6/timeTrackings/read/?start_time=2026-01-01&_op__start_time=gteq
        &_order_by=start_time&_sort_direction=DESC
OperatorMeaningOperatorMeaning
eqEquals (the default)likeSQL LIKE pattern match
neqNot equalinIn a comma-separated list
gtGreater thanninNot in a comma-separated list
gteqGreater than or equalbetwBetween two comma-separated bounds
ltLess thannullField is null
lteqLess than or equalnotnullField is not null

Shaping the response

ParameterPurpose
_fieldsComma-separated list of fields to return, instead of the full record. Worth using on wide resources.
_resolveComma-separated relations to expand inline, so you do not have to follow ids with extra calls. Resolved values come back under keys joined by __resolved__ — for example user_id__resolved__name.

Staying in sync

Rather than re-reading everything, ask for what changed. _since and _until bound the window by last-modified time, and _fetch_deleted is what makes deletions visible — without it a removed record simply stops appearing and your copy keeps a row that no longer exists.

ParameterPurpose
_sinceOnly rows modified at or after this date-time.
_untilOnly rows modified up to this date-time.
_fetch_deletedSet to 1 to include records deleted since _since. Supported on resources that track hard deletions.

The deltaSync resource does this across many resources in one call — see it in the reference.

When a call fails

StatusMeaning
400Malformed request — a required parameter is missing or unparseable.
401Missing, expired or invalid access token.
403Authenticated, but not permitted for this record.
410The resource is gone.
422Well-formed, but a value failed validation.
487Account is migrating or in maintenance — retry later.

Error responses carry a machine-readable code alongside the status; the full set is the ErrorCode schema in the reference.

Plans & features

Parts of the API are gated by the features your plan includes, and some features additionally require a particular seat on the user making the call. Endpoints in the reference carry a badge naming the feature they need.

What a plan includes is a default and can be overridden per customer, so no list published here would be true for every account. For what your own account actually has, call /v6/features/read/ — it answers per feature with enabled, the applicable limit and the seat types the feature requires, resolved against your current plan.

Availability is enforced per field as often as per endpoint: an endpoint may answer without the feature while rejecting particular fields or values. The badge names the feature and says which of the two applies, so treat it as "this needs feature X", not as "this endpoint is blocked".

Resources

74 resources, grouped by what they do. Select one to open it in the reference.

Devices & locations

3 resources · 11 endpoints

More resources

1 resources · 1 endpoints