Overview
The Platform API provides a comprehensive time tracking system with:
- Projects - Organize work by project with colors and descriptions
- Time Entries - Log hours worked with detailed information
- Categories - Classify time (training, travel, normal work, etc.)
- Client Billing - Track client work, sites, and billing rates
- Overtime Tracking - Automatic and manual overtime detection
- Manager Logging - Managers can log time on behalf of team members
Projects
Create Project
Projects help organize and categorize time entries:
POST /api/projects
Authorization: Bearer {token}
Content-Type: application/json
{
"companyId": "company-789",
"name": "Website Redesign",
"description": "Complete overhaul of company website",
"color": "#10B981",
"isActive": true
}
{
"success": true,
"data": {
"id": "proj-123",
"companyId": "company-789",
"name": "Website Redesign",
"description": "Complete overhaul of company website",
"color": "#10B981",
"isActive": true,
"createdAt": "2026-03-04T18:41:00Z",
"updatedAt": "2026-03-04T18:41:00Z"
}
}
List Projects
GET /api/projects?companyId={companyId}&isActive=true
Authorization: Bearer {token}
{
"success": true,
"data": [
{
"id": "proj-123",
"companyId": "company-789",
"name": "Website Redesign",
"description": "Complete overhaul of company website",
"color": "#10B981",
"isActive": true,
"createdAt": "2026-03-04T18:41:00Z"
},
{
"id": "proj-456",
"name": "Mobile App Development",
"description": "iOS and Android app",
"color": "#3B82F6",
"isActive": true,
"createdAt": "2026-03-01T10:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 2,
"totalPages": 1
}
}
Update Project
PATCH /api/projects/{projectId}
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "Website Redesign V2",
"isActive": false
}
Delete Project
DELETE /api/projects/{projectId}
Authorization: Bearer {token}
Deleting a project sets existing time entries’ projectId to NULL. Consider marking as inactive instead.
Project Colors
Use hex color codes for visual organization:
const projectColors = {
development: '#10B981', // Green
design: '#8B5CF6', // Purple
marketing: '#F59E0B', // Orange
support: '#EF4444', // Red
research: '#3B82F6', // Blue
admin: '#6B7280' // Gray
};
Time Entries
Create Time Entry
Log time worked by users:
POST /api/time-entries
Authorization: Bearer {token}
Content-Type: application/json
{
"companyId": "company-789",
"projectId": "proj-123",
"date": "2026-03-04",
"hours": 8.5,
"startTime": "09:00",
"endTime": "17:30",
"title": "Implemented user authentication",
"description": "Built JWT-based auth system with refresh tokens",
"categoryId": "cat-development",
"clientId": "client-acme",
"clientSiteId": "site-headquarters"
}
{
"success": true,
"data": {
"id": "entry-001",
"userId": "user-123",
"companyId": "company-789",
"projectId": "proj-123",
"date": "2026-03-04",
"hours": 8.5,
"startTime": "09:00",
"endTime": "17:30",
"title": "Implemented user authentication",
"description": "Built JWT-based auth system with refresh tokens",
"isOvertime": false,
"appliedRatePerHour": null,
"categoryId": "cat-development",
"clientId": "client-acme",
"clientSiteId": "site-headquarters",
"loggedByUserId": null,
"createdAt": "2026-03-04T18:41:00Z",
"updatedAt": "2026-03-04T18:41:00Z"
}
}
Manager Logs Time for Team Member
Managers can log time on behalf of their subordinates:
POST /api/time-entries
Authorization: Bearer {manager-token}
Content-Type: application/json
{
"companyId": "company-789",
"targetUserId": "user-456",
"date": "2026-03-04",
"hours": 4.0,
"title": "Client meeting",
"description": "Logged by manager - employee forgot to log"
}
Manager Logging: The targetUserId field specifies who the time is for, while loggedByUserId automatically tracks who created the entry.
List Time Entries
GET /api/time-entries?companyId={companyId}&startDate=2026-03-01&endDate=2026-03-31
Authorization: Bearer {token}
{
"success": true,
"data": [
{
"id": "entry-001",
"userId": "user-123",
"date": "2026-03-04",
"hours": 8.5,
"title": "Implemented user authentication",
"project": {
"id": "proj-123",
"name": "Website Redesign",
"color": "#10B981"
},
"user": {
"id": "user-123",
"email": "[email protected]",
"fullName": "John Doe"
},
"isOvertime": false,
"createdAt": "2026-03-04T18:41:00Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1,
"totalPages": 1
}
}
Filter Time Entries
Filter overtime entries only
Filter entries from this date (YYYY-MM-DD)
Filter entries until this date (YYYY-MM-DD)
Update Time Entry
PATCH /api/time-entries/{entryId}
Authorization: Bearer {token}
Content-Type: application/json
{
"hours": 9.0,
"endTime": "18:00",
"description": "Updated: Also added password reset functionality"
}
Delete Time Entry
DELETE /api/time-entries/{entryId}
Authorization: Bearer {token}
Time Entry Categories
Categories help classify different types of work:
Create Category
await prisma.timeEntryCategory.create({
data: {
companyId: "company-789",
name: "Training",
color: "#8B5CF6",
isDefault: false,
isActive: true,
createdBy: userId
}
});
Common Categories
Development
Regular development work
Meeting
Internal and client meetings
Training
Learning and skill development
Travel
Business travel time
Support
Customer support activities
Admin
Administrative tasks
Category Schema
model TimeEntryCategory {
id String @id @default(uuid())
companyId String @db.Uuid
name String @db.VarChar(100)
color String? @db.VarChar(7) @default("#6366F1")
isDefault Boolean @default(false)
isActive Boolean @default(true)
company Company @relation(fields: [companyId], references: [id])
timeEntries TimeEntry[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy String? @db.Uuid
@@unique([companyId, name])
@@index([companyId, isActive])
}
Client Billing
Clients
Track time for different clients:
await prisma.client.create({
data: {
companyId: "company-789",
name: "Acme Corporation",
taxId: "12-3456789",
email: "[email protected]",
phone: "+1234567890",
address: "123 Main St, San Francisco, CA 94105",
isActive: true,
isDefault: false,
createdBy: userId
}
});
Client Sites
Track work at different client locations:
await prisma.clientSite.create({
data: {
clientId: "client-acme",
name: "Headquarters",
address: "123 Main St",
city: "San Francisco",
isActive: true,
isDefault: true
}
});
Client Rate Rules
Define billing rates and overtime rules per client:
await prisma.clientRateRule.create({
data: {
clientId: "client-acme",
name: "Standard Contract 2026",
baseRatePerHour: 150.00,
overtimeRatePerHour: 225.00,
currency: "USD",
overtimeTriggers: ["WEEKEND", "AFTER_HOURS"],
workdayStartTime: "09:00",
workdayEndTime: "17:00",
workdays: [1, 2, 3, 4, 5], // Mon-Fri
isActive: true,
effectiveFrom: new Date("2026-01-01"),
effectiveTo: new Date("2026-12-31"),
createdBy: userId
}
});
Client Rate Resources
Different rates for different roles/resources:
await prisma.clientRateRuleResource.create({
data: {
rateRuleId: "rate-rule-123",
name: "Senior Developer",
baseRatePerHour: 175.00,
isActive: true
}
});
Overtime Triggers
WEEKEND - Work on Saturday (6) or Sunday (0)
AFTER_HOURS - Work outside workdayStartTime and workdayEndTime
MANUAL - Manually marked as overtime
Time Entry with Client Billing
POST /api/time-entries
Authorization: Bearer {token}
Content-Type: application/json
{
"companyId": "company-789",
"date": "2026-03-08",
"hours": 6.0,
"startTime": "10:00",
"endTime": "16:00",
"title": "Weekend deployment",
"description": "Emergency production deployment",
"isOvertime": true,
"clientId": "client-acme",
"clientSiteId": "site-headquarters",
"appliedRatePerHour": 225.00
}
The appliedRatePerHour can be automatically calculated based on client rate rules, or manually set for specific entries.
Time Summaries
Get Time Summary
Calculate totals for a date range:
GET /api/time-entries/summary?companyId={companyId}&startDate=2026-03-01&endDate=2026-03-31
Authorization: Bearer {token}
{
"success": true,
"data": {
"totalHours": 168.5,
"regularHours": 152.0,
"overtimeHours": 16.5,
"totalEntries": 21,
"breakdown": {
"byProject": [
{
"projectId": "proj-123",
"projectName": "Website Redesign",
"hours": 85.5
},
{
"projectId": "proj-456",
"projectName": "Mobile App Development",
"hours": 83.0
}
],
"byCategory": [
{
"categoryId": "cat-development",
"categoryName": "Development",
"hours": 140.0
},
{
"categoryId": "cat-meeting",
"categoryName": "Meeting",
"hours": 28.5
}
],
"byClient": [
{
"clientId": "client-acme",
"clientName": "Acme Corporation",
"hours": 120.0,
"estimatedRevenue": 18750.00
}
]
}
}
}
Best Practices
Time Entry Validation
Recommended Validations:
- Hours must be between 0.01 and 24
- Date cannot be in the future
startTime must be before endTime
- Title is required (1-200 characters)
projectId must belong to the same company
Use 24-hour format for start/end times:
"09:00" // 9:00 AM
"13:30" // 1:30 PM
"17:45" // 5:45 PM
"23:59" // 11:59 PM
Validation regex: ^([0-1][0-9]|2[0-3]):[0-5][0-9]$
Hours Calculation
Calculate hours from start/end times:
function calculateHours(startTime: string, endTime: string): number {
const [startHour, startMin] = startTime.split(':').map(Number);
const [endHour, endMin] = endTime.split(':').map(Number);
const startMinutes = startHour * 60 + startMin;
const endMinutes = endHour * 60 + endMin;
const diffMinutes = endMinutes - startMinutes;
return Number((diffMinutes / 60).toFixed(2));
}
const hours = calculateHours("09:00", "17:30"); // 8.5
Project Organization
Create Projects for Major Initiatives
Website redesign, mobile app, infrastructure upgrade
Use Colors for Visual Organization
Client work, internal projects, R&D, maintenance
Archive Completed Projects
Set isActive: false instead of deleting
Review Project List Regularly
Keep the active project list manageable (< 20 active projects)
Category Strategy
const categories = [
{ name: 'Development', color: '#10B981', isDefault: true },
{ name: 'Code Review', color: '#3B82F6', isDefault: false },
{ name: 'Testing', color: '#8B5CF6', isDefault: false },
{ name: 'Documentation', color: '#6366F1', isDefault: false },
{ name: 'Meeting', color: '#F59E0B', isDefault: false },
{ name: 'Training', color: '#EF4444', isDefault: false },
{ name: 'Support', color: '#EC4899', isDefault: false },
{ name: 'Admin', color: '#6B7280', isDefault: false }
];
Overtime Management
Automatic Overtime Detection:
Implement business logic to automatically detect overtime based on:
- Weekend work (workdays array)
- After-hours work (workdayStartTime/workdayEndTime)
- Daily/weekly hour thresholds
- Client-specific rules
Overtime Detection Example
function isOvertime(
date: Date,
startTime: string,
endTime: string,
rateRule: ClientRateRule
): boolean {
// Check weekend
const dayOfWeek = date.getDay();
if (rateRule.overtimeTriggers.includes('WEEKEND')) {
if (!rateRule.workdays.includes(dayOfWeek)) {
return true;
}
}
// Check after hours
if (rateRule.overtimeTriggers.includes('AFTER_HOURS')) {
if (startTime < rateRule.workdayStartTime ||
endTime > rateRule.workdayEndTime) {
return true;
}
}
return false;
}
Client Billing Setup
Create Client Record
Basic information, contact details, default status
Add Client Sites
If working at multiple client locations
Define Rate Rules
Base rates, overtime rates, effective dates
Add Rate Resources
Different rates for different roles (optional)
Log Time with Client
Link time entries to client and site
Generate Invoices
Use time entries and rates to calculate billing
Company Setup
Create companies for time tracking
User Management
Manage team members logging time
Permissions
Control access to time tracking
API Reference
View complete API documentation