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
Filter by status: “active” | “archived”
import { trpc } from '@/lib/trpc' ;
const projects = await trpc . trackerProjects . get . query ({
status: 'active' ,
});
trackerProjects.getById
Get a specific project by ID.
Whether the project is billable
Hourly rate for billable projects
Currency code for the rate
Total tracked seconds across all entries
const project = await trpc . trackerProjects . getById . query ({
id: 'project-uuid' ,
});
trackerProjects.upsert
Create a new project or update an existing one.
Project UUID (for updates, omit for new projects)
“active” | “archived” (default: “active”)
Whether the project is billable (default: false)
Hourly rate for billable projects
Currency code (required if rate is set)
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.
await trpc . trackerProjects . delete . mutate ({
id: 'project-uuid' ,
});
Time Entries
trackerEntries.byDate
Get time entries for a specific date.
Date in ISO format (YYYY-MM-DD)
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.
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.
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.
await trpc . trackerEntries . delete . mutate ({
id: 'entry-uuid' ,
});
Active Timer
trackerEntries.startTimer
Start a new timer.
Description of what you’re working on
User UUID (defaults to current user)
Start timestamp (ISO 8601)
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.
User UUID (defaults to current user)
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.
User UUID (defaults to current user)
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.
User UUID (defaults to current user)
Whether a timer is currently active
Active timer entry if running
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' ,
});