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.
  • 429 - Too Many Requests: You are being rate limited, try making fewer than 10 requests per second on average over any 5 minute period.
  • 500 - 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.

Security

Do NOT use the API with your secret key on a public website. Instead, create an embeddable chart that's safe to share publicly. Choose the JSON format to securely access your coding activity with JavaScript:

Embeddable SVG Charts and JSON

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.
  • https://wakatime.com/oauth/revoke - Make a server-side POST request here to invalidate a secret access token. Required x-www-form-urlencoded data is client_id, client_secret, and the token (access or refresh) to be invalidated.

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.

Using the Refresh Token

You should always get a refresh_token from the /oauth/token response. The refresh_token can be used when your access_token has expired, to re-authorize without having to prompt the user.

To use the refresh_token, make a POST request to https://wakatime.com/oauth/token to get a new 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 refresh_token, and the refresh_token received from a previous token response.

Revoking a Token

Your app should revoke tokens when users disconnect their WakaTime integration, delete their account on your app, or you no longer need access to a user’s account. To revoke an access token, and it’s corresponding refresh token, send a POST request to /oauth/revoke containing either JSON or form-urlencoded body containing your app’s client_id, client_secret, and the token (access or refresh token) that you would like to revoke. The response status will be 200 success if the token is successfully disabled. If the token is already revoked or expired, this endpoint will still respond with a 200 success response.

For example:

POST /oauth/revoke HTTP/1.1 Host: wakatime.com Content-Type: application/x-www-form-urlencoded client_id=XXX client_secret=sec_XXX token=sec_12345

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 coding activity and other stats.
  • write_logged_time - modify user’s coding activity.
  • read_stats - access user’s languages, editors, and operating systems used.
  • read_orgs - access user’s organizations, and coding activity for dashboard members.
  • read_private_leaderboards - access user’s private leaderboards.
  • write_private_leaderboards - modify user’s private leaderboards, including adding/removing members when current user had Admin or Owner role.

Example

OAuth 2.0 authentication flow using rauth (Python):

#!/usr/bin/env python

import hashlib
import os
import sys
from rauth import OAuth2Service

if sys.version_info[0] == 3:
    raw_input = input

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/oauth/test'
state = hashlib.sha1(os.urandom(40)).hexdigest()
params = {'scope': 'email,read_stats',
          'response_type': 'code',
          'state': state,
          'redirect_uri': redirect_uri}

url = service.get_authorize_url(**params)

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

# Make sure returned state has not changed for security reasons, and exchange
# code for an Access Token.
headers = {'Accept': 'application/x-www-form-urlencoded'}
print('Getting an access token...')
session = service.get_auth_session(headers=headers,
                                   data={'code': code,
                                         'grant_type': 'authorization_code',
                                         'redirect_uri': redirect_uri})

print('Getting current user from API...')
user = session.get('users/current').json()
print('Authenticated via OAuth as {0}'.format(user['data']['email']))
print("Getting user's coding stats from API...")
stats = session.get('users/current/stats')
print(stats.text)

Using refresh_token to get a new access_token when the previous one has expired, using rauth (Python):

from urllib.parse import parse_qsl

refresh_token = dict(parse_qsl(session.access_token_response.text))['refresh_token']

data = {
    'refresh_token': refresh_token,
    'grant_type': 'refresh_token',
}
session = service.get_auth_session(data=data)

400 Error (Invalid redirect_uri: Not valid for this client.)

If you see this error when running the example, add https://wakatime.com/oauth/test as an authorized redirect url in your App's settings.

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=

That’s because when you decode the base64 string "MTIzNDU=" you get "12345".

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

Do NOT use your API Key on a public website. Instead, use embeddable charts and JSON.

Writing your own plugin

WakaTime plugins are extensions that run inside your text editor or IDE sending usage stats, called heartbeats, to your WakaTime Dashboard. All official WakaTime plugins are open source on GitHub.

When building your own editor plugin, use our Creating a WakaTime plugin guide.

Embedding Charts & JSON

Want to share your WakaTime stats? Use the embeddable charts and JSON to safely embed your coding activity on a public website without leaking your secret api key. Select the JSON format for access to your coding stats in JavaScript. We don’t support Cross-Origin Resource Sharing (CORS) because the only way to access your coding stats safely in public JavaScript is with embeddable JSON. Embeddable JSON does support JSONP. Embeddable charts and JSON use a one-time unique url and can be retracted to prevent future access to your coding stats.

Never use the WakaTime API from a public website, except for embeddables. Using your secret api key in client-side JavaScript gives everyone on the internet full access to your WakaTime account.

All Time Since Today

GET /api/v1/users/:user/all_time_since_today

GET /api/v1/users/current/all_time_since_today

Description

The total time logged since account created, available even for Free accounts.

URL Parameters

project - String - optional - Shows the total time for a project, since project created.

Scope Required

read_stats

Example Response

Response Code: 200

Commit

GET /api/v1/users/:user/projects/:project/commits/:hash

GET /api/v1/users/current/projects/:project/commits/:hash

Description

A single commit from a WakaTime project showing the time spent coding on the commit.

URL Parameters

branch - String - optional - Filter the commit to a branch; defaults to the repo’s default branch name.

Scope Required

read_logged_time

Example Response

Response Code: 200

Commits

GET /api/v1/users/:user/projects/:project/commits

GET /api/v1/users/current/projects/:project/commits

Description

List of commits for a WakaTime project showing the time spent coding in each commit.

URL Parameters

author - String - optional - Filter commits to only those authored by the given username.

branch - String - optional - Filter commits to a branch; defaults to the repo’s default branch name.

page - Integer - optional - Page number of commits.

Scope Required

read_logged_time

Example Response

Response Code: 200

Data Dumps

GET /api/v1/users/:user/data_dumps

GET /api/v1/users/current/data_dumps

Description

List data exports for the user. A data export can also be created at https://wakatime.com/settings, and contains all the user’s coding stats as daily Summaries in JSON format since the user’s account was created.

Scope Required

read_logged_time

Example Response

Response Code: 200


POST /api/v1/users/:user/data_dumps

POST /api/v1/users/current/data_dumps

Description

Start generating a data export in the background. When finished, the percent complete will be 100 and the status 'Completed', with a 'download_url' available for downloading. An email will also be sent to the user with the download url when exporting completed.

Scope Required

read_logged_time

JSON POST Data

{
  "type": <string: Required export type; Either 'daily' or 'heartbeats'>,
  "email_when_finished": <boolean: Optional flag to disable the email notification when exporting completed; defaults to true>,
}

Example Response

Response Code: 201

Durations

GET /api/v1/users/:user/durations

GET /api/v1/users/current/durations

Description

A user's coding activity for the given day as an array of durations. Durations are read-only representations of Heartbeats, created by joining multiple Heartbeats together when they’re within 15 minutes of each other. The 15 minutes default can be changed with your account’s Keystroke Timeout preference.

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.

timeout - Integer - optional - The keystroke timeout preference used when joining heartbeats into durations. Defaults the the user's keystroke timeout value. See the FAQ for more info.

writes_only - Boolean - optional - The writes_only preference. Defaults to the user's writes_only setting.

timezone - String - optional - The timezone for given date. Defaults to the user's timezone.

slice_by - String - optional - Optional primary key to use when slicing durations. Defaults to “entity”. Can be “entity”, “language”, “dependencies”, “os”, “editor”, “category”, or “machine”.

Scope Required

read_logged_time

Example Response

Response Code: 200

Editors

GET /api/v1/editors

Description

List of WakaTime IDE plugins, latest plugin versions, and their color used on WakaTime charts.

URL Parameters

unreleased - Boolean - optional - Include unreleased plugins.

Example Response

Response Code: 200

Try it out

External Durations

GET /api/v1/users/:user/external_durations

GET /api/v1/users/current/external_durations

Description

A user's external durations for the given day. External durations aren’t created by IDE plugins. They’re created from external apps, such as the Google Calendar integration. They should be reproducible from the external integration. External durations for an integration are deleted when the user disconnects the integration from their WakaTime account.

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.

timezone - String - optional - The timezone for given date. Defaults to the user's timezone.

Scope Required

read_logged_time

Example Response

Response Code: 200


POST /api/v1/users/:user/external_durations

POST /api/v1/users/current/external_durations

POST /api/v1/users/:user/external_durations.bulk

POST /api/v1/users/current/external_durations.bulk

Description

Creates a duration representing activity for a user with start and end time, when Heartbeat pings aren’t available. For ex: meetings. External durations are not created by IDE plugins, only OAuth apps can create external durations. External durations must be created within one year from Today, and must not start before the associated user’s account was created. Use external_id to prevent creating duplicate durations. Using the same external_id will update any existing duration with the provided attributes. The bulk endpoint accepts an array of external durations, limited to 1,000 per POST request. The bulk endpoint will return 201 response status code with an array of status_codes for each duration sent. That’s because most invalid durations can be ommitted without problems while still allowing your app’s valid durations.

Scope Required

write_logged_time

JSON POST Data

{
  "external_id": <string: unique identifier for this duration on the external provider>,
  "entity": <string: entity which this duration is logging time towards, such as an absolute file path or a domain>,
  "type": <string: type of entity; can be file, app, or domain>,
  "category": <string: category for this activity (optional); normally this is inferred automatically from type; can be coding, building, indexing, debugging, browsing, running tests, writing tests, manual testing, writing docs, code reviewing, researching, learning, or designing>,
  "start_time": <float: UNIX epoch timestamp when the activity started; numbers after decimal point are fractions of a second>,
  "end_time": <float: UNIX epoch timestamp when the activity ended; numbers after decimal point are fractions of a second>,
  "project": <string: project name (optional)>,
  "branch": <string: branch name (optional)>,
  "language": <string: language name (optional)>,
}

Example Response

Response Code: 201

Goal

GET /api/v1/users/:user/goals/:goal

GET /api/v1/users/current/goals/:goal

Description

A single goal. This endpoint is only backed by cached data, similar to the Status Bar endpoint. If there’s no data yet in the cache, an empty Goal is returned while the cache updates in the background:
{"data":{"chart_data":[]}}.
Notice the keys present in the empty response are the only ones necessary for the wakatime-cli --today-goal command.

Scope Required

read_logged_time

Example Response

Response Code: 200

Goals

GET /api/v1/users/:user/goals

GET /api/v1/users/current/goals

Description

List a user’s goals.

Scope Required

read_logged_time

Example Response

Response Code: 200

Heartbeats

GET /api/v1/users/:user/heartbeats

GET /api/v1/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.

Scope Required

read_logged_time

Example Response

Response Code: 200


POST /api/v1/users/:user/heartbeats

POST /api/v1/users/current/heartbeats

POST /api/v1/users/:user/heartbeats.bulk

POST /api/v1/users/current/heartbeats.bulk

Description

Creates a heartbeat representing activity for a user. The bulk endpoint accepts an array of heartbeats, limited to 25 per POST request.

Scope Required

write_logged_time

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>,
  "category": <string: category for this activity (optional); normally this is inferred automatically from type; can be coding, building, indexing, debugging, browsing, running tests, writing tests, manual testing, writing docs, code reviewing, researching, learning, or designing>,
  "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 with the first line starting at 1 (optional)>,
  "cursorpos": <integer: current cursor column position starting from 1 (optional)>,
  "is_write": <boolean: whether this heartbeat was triggered from writing to a file (optional)>,
}

Example Response

Response Code: 201

Leaders

GET /api/v1/leaders

Description

List of users ranked by coding activity in descending order. Same as the public leaderboards. The public leaderboard updates at least once every 12 hours, and usually more frequently.

URL Parameters

language - String - optional - Filter leaders by a specific language.

is_hireable - Boolean - optional - Filter leaders by the hireable badge.

country_code - String - optional - Filter leaders by two-character country code.

page - Integer - optional - Page number of leaderboard. If authenticated, defaults to the page containing the currently authenticated user.

Example Response

Response Code: 200

Try it out

Machine Names

GET /api/v1/users/:user/machine_names

GET /api/v1/users/current/machine_names

Description

List of machines for this user.

Scope Required

read_logged_time

Example Response

Response Code: 200

Meta

GET /api/v1/meta

Description

Information about WakaTime, such as a list of public ip addresses used by WakaTime servers.

Example Response

Response Code: 200

Try it out

Org Dashboard Member Durations

GET /api/v1/users/:user/orgs/:org/dashboards/:dashboard/members/:member/durations

GET /api/v1/users/current/orgs/:orgs/dashboards/:dashboard/members/:member/durations

Description

A dashboard member's coding activity for the given day as an array of durations.

URL Parameters

date - Date - required - Date in YYYY-MM-DD format.

project - String - optional - Only show durations for this project.

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

Scope Required

read_orgs

Example Response

Response Code: 200

Org Dashboard Member Summaries

GET /api/v1/users/:user/orgs/:org/dashboards/:dashboard/members/:member/summaries

GET /api/v1/users/current/orgs/:org/dashboards/:dashboard/members/:member/summaries

Description

An organization dashboard member’s coding activity 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 coding activity for these branches; comma separated list of branch names.

range - String - optional - Alternative way to supply start and end dates. Can be one of “Today”, “Yesterday”, “Last 7 Days”, “Last 7 Days from Yesterday”, “Last 14 Days”, “Last 30 Days”, “This Week”, “Last Week”, “This Month”, or “Last Month”.

Scope Required

read_orgs

Example Response

Response Code: 200

Org Dashboard Members

GET /api/v1/users/:user/orgs/:org/dashboards/:dashboard/members

GET /api/v1/users/current/orgs/:org/dashboards/:dashboard/members

Description

List an organization’s members.

Scope Required

read_orgs

Example Response

Response Code: 200

Org Dashboards

GET /api/v1/users/:user/orgs/:org/dashboards

GET /api/v1/users/current/orgs/:org/dashboards

Description

List the organization’s dashboards.

Scope Required

read_orgs

Example Response

Response Code: 200

Orgs

GET /api/v1/users/:user/orgs

GET /api/v1/users/current/orgs

Description

List a user’s organizations.

Scope Required

read_orgs

Example Response

Response Code: 200

Private Leaderboards

GET /api/v1/users/:user/leaderboards

GET /api/v1/users/current/leaderboards

Description

List user’s private leaderboards. Same as this page.

Scope Required

read_private_leaderboards

Example Response

Response Code: 200

Try it out

Private Leaderboards Leaders

GET /api/v1/users/:user/leaderboards/:board

GET /api/v1/users/current/leaderboards/:board

Description

List of users in this private leaderboard ranked by coding activity in descending order.

URL Parameters

language - String - optional - Filter leaders by a specific language.

country_code - String - optional - Filter leaders by two-character country code.

page - Integer - optional - Page number of leaderboard. If authenticated, defaults to the page containing the currently authenticated user.

Scope Required

read_private_leaderboards

Example Response

Response Code: 200

Projects

GET /api/v1/users/:user/projects

GET /api/v1/users/current/projects

Description

List of WakaTime projects for the current user.

URL Parameters

q - String - optional - Filter project names by a search term.

Scope Required

read_logged_time

Example Response

Response Code: 200

Stats

GET /api/v1/users/:user/stats/:range

GET /api/v1/users/current/stats/:range

Description

A user's coding activity for the given time range. range can be one of last_7_days, last_30_days, last_6_months, or last_year. For accounts subscribed to the free plan, time ranges >= one year are updated on the first request. It’s best to always check is_up_to_date and retry your request when the response is stale. Stats are read-only representations of Heartbeats, Durations, and Summaries, created by joining multiple Heartbeats together when they’re within 15 minutes of each other. The 15 minutes default can be changed with your account’s Keystroke Timeout preference.

URL Parameters

timeout - Integer - optional - The keystroke timeout value used to calculate these stats. Defaults the the user's keystroke 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.

Scope Required

read_stats

Example Response

Response Code: 200

Stats Aggregated

GET /api/v1/stats/:range

Description

Aggregate stats of all WakaTime users over the given time range. range can be one of last_7_days or any year in the past since 2013 for ex: 2020. Aggregate stats are only available with the same preferences as public profiles (Default 15m keystroke timeout preference). Yearly aggregate stats are calculated each year on Jan 1st.

Example Response

Response Code: 200

Try it out

Status Bar

GET /api/v1/users/:user/status_bar/today

GET /api/v1/users/current/status_bar/today

Description

A user’s coding activity today for displaying in IDE text editor status bars. This is the same as Summaries with range of “Today”. This endpoint is only backed by cached data. If there’s no data yet in the cache, an empty Summary is returned while the cache updates in the background:
{"data":{"grand_total":{"text":""},"categories":[],"range":{"text":"Today","timezone":"UTC"}}}.
Notice the keys present in the empty response are the only ones necessary for the wakatime-cli --today command.

Scope Required

read_logged_time

Example Response

Response Code: 200

Summaries

GET /api/v1/users/:user/summaries

GET /api/v1/users/current/summaries

Description

A user's coding activity for the given time range as an array of summaries segmented by day. Summaries are read-only representations of Heartbeats and Durations, created by joining multiple Heartbeats together when they’re within 15 minutes of each other. The 15 minutes default can be changed with your account’s Keystroke Timeout preference.

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 coding activity for these branches; comma separated list of branch names.

timeout - Integer - optional - The keystroke timeout preference used when joining heartbeats into durations. Defaults the the user's keystroke timeout value. See the FAQ for more info.

writes_only - Boolean - optional - The writes_only preference. Defaults to the user's writes_only setting.

timezone - String - optional - The timezone for given start and end dates. Defaults to the user's timezone.

range - String - optional - Alternative way to supply start and end dates. Can be one of “Today”, “Yesterday”, “Last 7 Days”, “Last 7 Days from Yesterday”, “Last 14 Days”, “Last 30 Days”, “This Week”, “Last Week”, “This Month”, or “Last Month”.

Scope Required

read_logged_time

Example Response

Response Code: 200

User Agents

GET /api/v1/users/:user/user_agents

GET /api/v1/users/current/user_agents

Description

List of plugins which have sent data for this user.

Scope Required

read_logged_time

Example Response

Response Code: 200

Users

GET /api/v1/users/:user

GET /api/v1/users/current

Description

A single user.

Scope Required

email

Example Response

Response Code: 200