Documentation

API Reference

Authentication, activity ingestion, category overrides, extension remote control, focus sessions and settings.

All routes are prefixed with https://api.timelens.app/api. Every route except /auth/* and the health checks requires a bearer token.

Authentication

http
Authorization: Bearer <accessToken>
Content-Type: application/json

The desktop app and the extension both authenticate through the same token service. Tokens are account scoped, so a request only ever reads or writes the authenticated user's own rows.

Authentication routes

MethodPathDescription
POST/auth/registerCreate an account
POST/auth/verify-emailConfirm an email address with the code sent at registration
POST/auth/loginEmail and password sign-in
POST/auth/logoutInvalidate the current session
POST/auth/oauthSign in with Google or GitHub
POST/auth/forgot-passwordRequest a password reset
POST/auth/reset-passwordComplete a password reset
POST/auth/desktop-registerRegister from the desktop app
POST/auth/desktop-verify-emailVerify the email used by the desktop app
POST/auth/desktop-resend-codeResend a verification code
POST/auth/extension-loginExchange extension credentials for a token
POST/auth/extension-oauthOAuth sign-in originating from the extension
GET/auth/meCurrent user profile
PATCH/auth/meUpdate the current user profile

Activity

MethodPathDescription
POST/activitiesSubmit a completed activity block
GET/activitiesList activities in a range with filters
GET/activities/summaryTotals and aggregates for the dashboard
PUT/activities/overrideReclassify a website for this user only
DELETE/activities/overrideRemove a user classification override
POST/activities

Submit a completed activity block. Accepts desktop application activity or browser domain activity.

Request

{
  "source": "desktop",
  "appName": "Visual Studio Code",
  "startedAt": "2026-01-14T09:00:00.000Z",
  "endedAt": "2026-01-14T09:42:00.000Z",
  "durationMinutes": 42
}

Response

{
  "success": true,
  "activity": { "id": "clx...", "category": "Development" }
}
POST/activities

Browser activity uses a domain instead of an application name. The extension resolves the category locally and the server applies any per-user override on top.

Request

{
  "source": "browser",
  "domain": "github.com",
  "title": "Pull requests",
  "startedAt": "2026-01-14T09:42:00.000Z",
  "endedAt": "2026-01-14T10:00:00.000Z",
  "durationMinutes": 18
}

Extension remote control

The desktop app can pause tracking remotely. The extension heartbeats so the dashboard knows it is alive, and polls a pending control command that it then acknowledges.

MethodPathDescription
POST/activities/heartbeatExtension liveness signal
GET/activities/extension-statusRead the last heartbeat and control state
PUT/activities/extension-controlSet tracking state for the extension
GET/activities/extension-control/pendingPoll for a control command
POST/activities/extension-control/ackAcknowledge a command

Focus sessions and settings

MethodPathDescription
POST/focus-sessionsRecord a completed or elapsed focus session
GET/settingsRead focus durations and tracking preferences
PUT/settingsUpdate focus durations and tracking preferences
POST/focus-sessions

A focus session contributes to Focused Time only. Total and Productive time are derived from activity, not from this payload.

Request

{
  "mode": "pomodoro",
  "plannedMinutes": 25,
  "elapsedMinutes": 25,
  "completedAt": "2026-01-14T10:15:00.000Z"
}

Health

MethodPathDescription
GET/healthLiveness, no authentication
GET/db-testRound-trips a query to verify database connectivity

Error format

json
{ "error": "Invalid credentials.", "field": "email" }