Introduction

The WakaTime API follows common REST conventions. This means you should use GET requests to retrieve data and POST, PUT, or PATCH requests to modify data. All API requests must be done over HTTPS.

Every response will be a JSON object, which is a key-value hash. Data for a resource will be returned in the key named data. Errors will be returned in the key named errors or error.

HTTP response codes indicate the status of your request:

  • 200 - Ok: The request has succeeded.
  • 201 - Created: The request has been fulfilled and resulted in a new resource being created.
  • 202 - Accepted: The request has been accepted for processing, but the processing has not been completed. The stats resource may return this code.
  • 400 - Bad Request: The request is invalid. Check error message and try again.
  • 401 - Unauthorized: The request requires authentication, or your authentication was invalid.
  • 403 - Forbidden: You are authenticated, but do not have permission to access the resource.
  • 404 - Not Found: The resource does not exist.
  • 50x - Server Error: Service unavailable, try again later.

All API resources have the url prefix https://wakatime.com/api/v1/.

When using the WakaTime trademark or logo in your application, please follow our usage guidelines.

Using Postman

The Postman Chrome Extension is a great way to get started with the WakaTime API. Download the extension here, click Collections, then click Import collection.

Import this WakaTime API Postman Collection to start using the WakaTime api right away. Remember to add your API key to authenticate your requests.

Authentication

OAuth 2.0 Endpoints

Create an app to get an OAuth 2.0 client token.

The OAuth 2.0 provider endpoints are:

  • https://wakatime.com/oauth/authorize - Redirect your users here to request permission to access their account. Required url arguments are client_id, response_type of code or token, redirect_uri, scope. Optional parameters are state and force_approve.
  • https://wakatime.com/oauth/token - Make a server-side POST request here to get the secret access token. Required x-www-form-urlencoded data is client_id, client_secret, redirect_uri must be the same url used in authorize step, grant_type of authorization_code, and the code received from the authorize step.

For information about using these endpoints, see RFC6749 OAuth 2.0.

Using Access Token

After getting the bearer (access) token from https://wakatime.com/oauth/token, you can now make authenticated api calls using the Authorization request header (RFC 6750).

For example, if your user's access token is sec_12345, you would add this header to your request:
Authorization: Bearer sec_12345.

Alternatively, you can authenticate with url args named access_token, or just token and app_secret, client_secret, or just secret.

Available Scopes

Scopes are sent to the authorize url as a comma separated list.

  • email - access user's email and identity information.
  • read_logged_time - access user's logged time and other stats.
  • write_logged_time - write heartbeats as this user.
  • read_stats - access user's languages, editors, and operating systems used.
  • read_teams - access user's team membership, along with coding activity for members of user's teams .

Example

OAuth 2.0 authentication flow using rauth (Python):

#!/usr/bin/env python

import hashlib
import os
from rauth import OAuth2Service

client_id = raw_input('Enter your App Id: ')
secret = raw_input('Enter your App Secret: ')

service = OAuth2Service(
    client_id=client_id, # your App ID from https://wakatime.com/apps
    client_secret=secret, # your App Secret from https://wakatime.com/apps
    name='wakatime',
    authorize_url='https://wakatime.com/oauth/authorize',
    access_token_url='https://wakatime.com/oauth/token',
    base_url='https://wakatime.com/api/v1/')

redirect_uri = 'https://wakatime.com/login_ok'
state = hashlib.sha1(os.urandom(40)).hexdigest()
params = {'scope': 'email,read_logged_time',
          'response_type': 'code',
          'state': state,
          'redirect_uri': redirect_uri}

url = service.get_authorize_url(**params)

print('**** Visit {url} in your browser. ****'.format(url=url))
print('**** After clicking Authorize, paste code here and press Enter ****')
code = raw_input('Enter code from url: ')

# the code should be returned upon the redirect from the authorize step,
# be sure to use it here (hint: it's in the URL!)
# also, make sure returned state has not changed for security reasons.
headers = {'Accept': 'application/x-www-form-urlencoded'}
session = service.get_auth_session(headers=headers,
                                   data={'code': code,
                                         'grant_type': 'authorization_code',
                                         'redirect_uri': redirect_uri})

print(session.get('users/current').json()['data']['email'])

Using API Key

Most apps should use OAuth, but you can also authenticate to the WakaTime API using your secret API key .

Using HTTP Basic Auth pass your API key base64 encoded in the Authorization header. Don't forget to prepend Basic to your api key after base64 encoding it.

For example, when using HTTP Basic Auth with an api key of 12345 you should add this header to your request:
Authorization: Basic MTIzNDU=

Alternatively, you can pass your api key as a query parameter in your request like ?api_key=XXXX.

Durations

GET users/:user/durations

GET users/current/durations

Description

A user's logged time for the given day as an array of duration blocks.

URL Parameters

date (Date) - required - Requested day; Durations will be returned from 12am until 11:59pm in user's timezone for this day.

project (string) - optional - Only show durations for this project.

branches (string) - optional - Only show durations for these branches; comma separated list of branch names.

Example Response

Response Code: 200

{
  "data": [
    {
      "project": <string: project name>,
      "time": <float: start of this duration as ISO 8601 UTC datetime; numbers after decimal point are fractions of a second>,
      "duration": <integer: length of time of this duration in seconds>
    }, ...
  ],
  "branches": <list of strings: branches included in this response>,
  "start": <integer: start of time range as ISO 8601 UTC datetime>,
  "end": <integer: end of time range as ISO 8601 UTC datetime>,
  "timezone": <string: timezone used for this request in Olson Country/Region format>
}

Heartbeats

GET users/:user/heartbeats

GET users/current/heartbeats

Description

A user's heartbeats sent from plugins for the given day as an array.

URL Parameters

date (Date) - required - Requested day; Heartbeats will be returned from 12am until 11:59pm in user's timezone for this day.

Example Response

Response Code: 200

{
  "data": [
    {
      "entity": <string: entity heartbeat is logging time against, such as an absolute file path or domain>,
      "type": <string: type of entity; can be file, app, or domain>,
      "time": <float: UNIX epoch timestamp; numbers after decimal point are fractions of a second>,
      "project": <string: project name (optional)>,
      "branch": <string: branch name (optional)>,
      "language": <string: language name (optional)>,
      "dependencies": <string: optional comma separated list of dependencies detected from entity file (optional)>,
      "lines": <integer: total number of lines in the entity (when entity type is file)>,
      "lineno": <integer: current line row number of cursor (optional)>,
      "cursorpos": <integer: current cursor column position (optional)>,
      "is_write": <boolean: whether this heartbeat was triggered from writing to a file>,
      "is_debugging": <boolean: whether this heartbeat was triggered while debuggging>,
    }, ...
  ],
  "start": <integer: start of time range as ISO 8601 UTC datetime>,
  "end": <integer: end of time range as ISO 8601 UTC datetime>,
  "timezone": <string: timezone used for this request in Olson Country/Region format>
}


POST users/:user/heartbeats

POST users/current/heartbeats

Description

Creates a heartbeat representing activity for a user.

URL Parameters

None

JSON POST Data

{
  "entity": <string: entity heartbeat is logging time against, such as an absolute file path or domain>,
  "type": <string: type of entity; can be file, app, or domain>,
  "time": <float: UNIX epoch timestamp; numbers after decimal point are fractions of a second>,
  "project": <string: project name (optional)>,
  "branch": <string: branch name (optional)>,
  "language": <string: language name (optional)>,
  "dependencies": <string: comma separated list of dependencies detected from entity file (optional)>,
  "lines": <integer: total number of lines in the entity (when entity type is file)>,
  "lineno": <integer: current line row number of cursor (optional)>,
  "cursorpos": <integer: current cursor column position (optional)>,
  "is_write": <boolean: whether this heartbeat was triggered from writing to a file (optional)>,
  "is_debugging": <boolean: whether this heartbeat was triggered while debuggging (optional)>,
}

Example Response

Response Code: 201

{
  "data": {
    "id": <string: unique id of newly created heartbeat>,
    "entity": <string: entity heartbeat is logging time against, such as an absolute file path or domain>,
    "type": <string: type of entity; can be file, app, or domain>,
    "time": <float: UNIX epoch timestamp; numbers after decimal point are fractions of a second>,
  }
}

Leaders

GET leaders

Description

List of users ranked by logged time in descending order. Same as the public leaderboards.

URL Parameters

language (string) - optional - filter leaders by a specific language.

Example Response

{
  "data": [
    {
      "rank": <integer: rank of this leader>,
      "running_total": {
        "total_seconds": <integer: total logged time for this user as seconds>,
        "human_readable_total": <string: total logged time for this user as human readable string>,
        "daily_average": <integer: daily average for this user as seconds>,
        "human_readable_daily_average": <string: daily average for this user as human readable string>,
        "languages": [
          {
            "name": <string: language name>,
            "total_seconds": <integer: total seconds user has logged in this language>,
          }, ...
        ],
      },
      "user": {
        "id": <string: unique id of user>,
        "email": <string: email address of user, if public>,
        "username": <string: users public username>,
        "full_name": <string: full name of user>,
        "display_name": <string: display name of this user taken from full_name or @username. Defaults to 'Anonymous User'>,
        "website": <string: website of user>,
        "human_readable_website": <string: website of user without url scheme>,
        "location": <string: location of user>,
        "email_public": <boolean: whether this user's email should be shown publicly on leader boards>,
        "photo_public": <boolean: whether this user's photo should be shown publicly on leader boards>,
      },
    }, ...
  ],
  "range": <string: time range of this leaderboard>,
  "language": <string: language of this leaderboard>,
}

Try it out

Stats

GET users/:user/stats/:range

GET users/current/stats/:range

Description

A user's logged time for the given time range. range can be one of last_7_days, last_30_days, last_6_months, or last_year.

URL Parameters

timeout (integer) - optional - The timeout value used to calculate these stats. Defaults the the user's timeout value.

writes_only (boolean) - optional - The writes_only value used to calculate these stats. Defaults to the user's writes_only setting.

project (string) - optional - Show more detailed stats limited to this project.

Example Response

{
  "data": [
    {
      "total_seconds": <integer: total logged time as seconds for the given range of time>,
      "human_readable_total": <string: total logged time as human readable string>,
      "daily_average": <integer: average coding activity per day as seconds for the given range of time>,
      "human_readable_daily_average": <string: daily average as human readable string>,
      "projects": [
        {
          "name": <string: project name>,
          "total_seconds": <integer: total logged time as seconds>,
          "percent": <float: percent of time spent in this project>,
          "digital": <string: total logged time for this project in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this project>,
          "minutes": <integer: minutes portion of logged time for this project>
        }, ...
      ],
      "languages": [
        {
          "name": <string: language name>,
          "total_seconds": <integer: total logged time spent in this language as seconds>,
          "percent": <float: percent of time spent in this language>,
          "digital": <string: total logged time for this language in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this language>,
          "minutes": <integer: minutes portion of logged time for this language>,
          "seconds": <integer: seconds portion of logged time for this language>
        }, ...
      ],
      "editors": [
        {
          "name": <string: editor name>,
          "total_seconds": <integer: total logged time spent in this editor as seconds>,
          "percent": <float: percent of time spent in this editor>,
          "digital": <string: total logged time for this editor in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this editor>,
          "minutes": <integer: minutes portion of logged time for this editor>,
          "seconds": <integer: seconds portion of logged time for this editor>
        }, ...
      ],
      operating_systems: [
        {
          "name": <string: os name>,
          "total_seconds": <integer: total logged time spent in this os as seconds>,
          "percent": <float: percent of time spent in this os>,
          "digital": <string: total logged time for this os in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this os>,
          "minutes": <integer: minutes portion of logged time for this os>,
          "seconds": <integer: seconds portion of logged time for this os>
        }, ...
      ],
      "best_day": {
        "date": <string: day with most coding time logged as Date string in YEAR-MONTH-DAY format>,
        "total_seconds": <integer: number of seconds of coding activity for this day>
      },
      "range": <string: time range of these stats>,
      "holidays": <integer: number of days in this range with no coding time logged>,
      "days_including_holidays": <integer: number of days in this range>,
      "days_minus_holidays": <integer: number of days in this range excluding days with no coding time logged>,
      "status": <string: status of these stats in the cache>,
      "is_already_updating": <boolean: true if these stats are being updated in the background>,
      "is_stuck": <boolean: true if these stats got stuck while processing and will be recalculated in the background>,
      "is_up_to_date": <boolean: true if these stats are up to date>,
      "start": <integer: start of this time range as ISO 8601 UTC datetime>,
      "end": <integer: end of this time range as ISO 8601 UTC datetime>,
      "timezone": <string: timezone used in Olson Country/Region format>,
      "timeout": <integer: value of the user's timeout setting in minutes>,
      "writes_only": <boolean: status of the user's writes_only setting>,
      "user_id": <string: unique id of this user>,
      "username": <string: public username for this user>,
      "created_at": <datetime: time when these stats were created in ISO 8601 format>,
      "modified_at": <datetime: time when these stats were last updated in ISO 8601 format>
    }, ...
  ],
}

Summaries

GET users/:user/summaries

GET users/current/summaries

Description

A user's logged time for the given time range as an array of summaries segmented by day.

URL Parameters

start (Date) - required - Start date of the time range.

end (Date) - required - End date of the time range.

project (string) - optional - Only show time logged to this project.

branches (string) - optional - Only show logged time for these branches; comma separated list of branch names.

Example Response

Response Code: 200

{
  "data": [
    {
      "grand_total": {
        "digital": <string: total logged time in digital clock format>,
        "hours": <integer: hours portion of logged time>,
        "minutes": <integer: minutes portion of logged time>,
        "text": <string: total logged time in human readable format>,
        "total_seconds": <integer: total logged time as seconds>
      },
      "projects": [
        {
          "name": <string: project name>,
          "total_seconds": <integer: total logged time as seconds>,
          "percent": <float: percent of time spent in this project>,
          "digital": <string: total logged time for this project in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this project>,
          "minutes": <integer: minutes portion of logged time for this project>
        }, ...
      ],
      "languages": [
        {
          "name": <string: language name>,
          "total_seconds": <integer: total logged time spent in this language as seconds>,
          "percent": <float: percent of time spent in this language>,
          "digital": <string: total logged time for this language in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this language>,
          "minutes": <integer: minutes portion of logged time for this language>,
          "seconds": <integer: seconds portion of logged time for this language>
        }, ...
      ],
      "editors": [
        {
          "name": <string: editor name>,
          "total_seconds": <integer: total logged time spent in this editor as seconds>,
          "percent": <float: percent of time spent in this editor>,
          "digital": <string: total logged time for this editor in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this editor>,
          "minutes": <integer: minutes portion of logged time for this editor>,
          "seconds": <integer: seconds portion of logged time for this editor>
        }, ...
      ],
      operating_systems: [
        {
          "name": <string: os name>,
          "total_seconds": <integer: total logged time spent in this os as seconds>,
          "percent": <float: percent of time spent in this os>,
          "digital": <string: total logged time for this os in digital clock format>,
          "text": <string: total logged time in human readable format>,
          "hours": <integer: hours portion of logged time for this os>,
          "minutes": <integer: minutes portion of logged time for this os>,
          "seconds": <integer: seconds portion of logged time for this os>
        }, ...
      ],
      "range": {
        "date": <string: this day as Date string in YEAR-MONTH-DAY format>,
        "start": <integer: start of this day as ISO 8601 UTC datetime>,
        "end": <integer: end of this day as ISO 8601 UTC datetime>,
        "text": <string: this day in human-readable format relative to the current day>,
        "timezone": <string: timezone used in Olson Country/Region format>
      }
    }, ...
  ],
  "start": <integer: start of time range as ISO 8601 UTC datetime>,
  "end": <integer: end of time range as ISO 8601 UTC datetime>,
}

Users

GET users/:user

GET users/current

Description

A single user.

URL Parameters

None

Example Response

Response Code: 200

{
  "data": {
    "id": <string: unique id of user>,
    "email": <string: email address>,
    "timezone": <string: user's timezone in Olson Country/Region format>,
    "last_heartbeat": <datetime: time of most recent heartbeat logged by this user>,
    "last_plugin": <string: last plugin used by this user>,
    "last_project": <string: name of last project logged by this user>,
    "plan": <string: users subscription plan>,
    "username": <string: users public username>,
    "profile": {
      "logged_time_public": <boolean: whether this user's logged time should be shown publicly on leader boards>,
      "languages_used_public": <boolean: whether this user's languages used should be shown publicly on leader boards>,
      "email_public": <boolean: whether this user's email should be shown publicly on leader boards>,
      "photo_public": <boolean: whether this user's photo should be shown publicly on leader boards>,
    },
    "created_at": <datetime: time when user was created in ISO 8601 format>,
    "modified_at": <datetime: time when user was last modified in ISO 8601 format>,
  },
}

User Agents

GET users/:user/user_agents

GET users/current/user_agents

Description

List of plugins which have sent data for this user.

URL Parameters

None

Example Response

Response Code: 200

{
  "data": {
    "id": <string: unique id of this user agent>,
    "value": <string: a user agent string>,
    "editor": <string: the editor/IDE name of this user agent>,
    "version": <string: the wakatime plugin version of this user agent>,
    "os": <string: operating system of this user agent>,
    "last_seen": <datetime: time when this user agent was last seen in ISO 8601 format>,
    "created_at": <datetime: time when this user agent was first seen in ISO 8601 format>,
  },
}