Skip to main content
The Time Tracker API provides endpoints for tracking time spent on projects, managing time entries, and controlling active timers.

Projects

trackerProjects.get

Retrieve a list of tracker projects.
Search query for project name
status
string
Filter by status: “active” | “archived”
sort
array
Array of sort objects
import { trpc } from '@/lib/trpc';

const projects = await trpc.trackerProjects.get.query({
  status: 'active',
});

trackerProjects.getById

Get a specific project by ID.
id
string
required
Project UUID
project
object
const project = await trpc.trackerProjects.getById.query({
  id: 'project-uuid',
});

trackerProjects.upsert

Create a new project or update an existing one.
id
string
Project UUID (for updates, omit for new projects)
name
string
required
Project name
description
string
Project description
status
string
“active” | “archived” (default: “active”)
billable
boolean
Whether the project is billable (default: false)
rate
number
Hourly rate for billable projects
currency
string
Currency code (required if rate is set)
customerId
string
Customer UUID to associate with this project
// Create new billable project
const project = await trpc.trackerProjects.upsert.mutate({
  name: 'Website Redesign',
  description: 'Complete redesign of corporate website',
  billable: true,
  rate: 150,
  currency: 'USD',
  customerId: 'customer-uuid',
});

// Update existing project
await trpc.trackerProjects.upsert.mutate({
  id: 'project-uuid',
  status: 'archived',
});

trackerProjects.delete

Delete a project.
id
string
required
Project UUID
await trpc.trackerProjects.delete.mutate({
  id: 'project-uuid',
});

Time Entries

trackerEntries.byDate

Get time entries for a specific date.
date
string
required
Date in ISO format (YYYY-MM-DD)
entries
array
Array of time entry objects for the specified date
const entries = await trpc.trackerEntries.byDate.query({
  date: '2024-11-15',
});

trackerEntries.byRange

Get time entries within a date range.
from
string
required
Start date (ISO format)
to
string
required
End date (ISO format)
projectId
string
Filter by project UUID
result
object
Object with dates as keys and arrays of entries as values
const { result } = await trpc.trackerEntries.byRange.query({
  from: '2024-11-01',
  to: '2024-11-30',
  projectId: 'project-uuid',
});

// result = {
//   '2024-11-01': [entry1, entry2],
//   '2024-11-02': [entry3],
//   ...
// }

trackerEntries.upsert

Create or update time entries.
entries
array
required
Array of entry objects to upsert
type TimeEntry = {
  id?: string;          // UUID (omit for new entries)
  projectId: string;    // Project UUID
  date: string;         // Date (YYYY-MM-DD)
  duration: number;     // Duration in seconds
  description?: string; // Entry description
  start?: string;       // Start time (ISO 8601)
  stop?: string;        // Stop time (ISO 8601)
};
await trpc.trackerEntries.upsert.mutate({
  entries: [
    {
      projectId: 'project-uuid',
      date: '2024-11-15',
      duration: 7200, // 2 hours in seconds
      description: 'Frontend development',
    },
  ],
});

trackerEntries.delete

Delete a time entry.
id
string
required
Entry UUID
await trpc.trackerEntries.delete.mutate({
  id: 'entry-uuid',
});

Active Timer

trackerEntries.startTimer

Start a new timer.
projectId
string
required
Project UUID
description
string
Description of what you’re working on
assignedId
string
User UUID (defaults to current user)
timer
object
const timer = await trpc.trackerEntries.startTimer.mutate({
  projectId: 'project-uuid',
  description: 'Working on authentication',
});

console.log('Timer started at:', timer.start);

trackerEntries.stopTimer

Stop the active timer.
assignedId
string
User UUID (defaults to current user)
entry
object
The completed time entry with calculated duration
const entry = await trpc.trackerEntries.stopTimer.mutate({});

console.log('Tracked duration:', entry.duration, 'seconds');

trackerEntries.getCurrentTimer

Get the currently active timer.
assignedId
string
User UUID (defaults to current user)
timer
object
Active timer object or null if no timer is running
const timer = await trpc.trackerEntries.getCurrentTimer.query();

if (timer) {
  console.log('Timer running for project:', timer.projectId);
} else {
  console.log('No active timer');
}

trackerEntries.getTimerStatus

Get timer status information.
assignedId
string
User UUID (defaults to current user)
status
object
const { isRunning, entry } = await trpc.trackerEntries.getTimerStatus.query();

if (isRunning) {
  const elapsed = Date.now() - new Date(entry.start).getTime();
  console.log('Timer running for:', Math.floor(elapsed / 1000), 'seconds');
}

Invoicing from Time Tracking

Billable projects can be converted to invoices using the createFromTracker procedure in the Invoice API.
// Create invoice from tracked time
const invoice = await trpc.invoice.createFromTracker.mutate({
  projectId: 'project-uuid',
  dateFrom: '2024-11-01',
  dateTo: '2024-11-30',
});

// Invoice will have a line item with:
// - Total hours tracked in the period
// - Project's hourly rate
// - Total amount calculated automatically

Example: Complete Workflow

// 1. Create a billable project
const project = await trpc.trackerProjects.upsert.mutate({
  name: 'Client Website',
  billable: true,
  rate: 150,
  currency: 'USD',
  customerId: 'customer-uuid',
});

// 2. Start tracking time
const timer = await trpc.trackerEntries.startTimer.mutate({
  projectId: project.id,
  description: 'Homepage redesign',
});

// ... work on the project ...

// 3. Stop the timer
const entry = await trpc.trackerEntries.stopTimer.mutate({});
console.log('Tracked:', entry.duration / 3600, 'hours');

// 4. At end of month, create invoice
const invoice = await trpc.invoice.createFromTracker.mutate({
  projectId: project.id,
  dateFrom: '2024-11-01',
  dateTo: '2024-11-30',
});

Build docs developers (and LLMs) love