This document provides comprehensive reference documentation for all API endpoints in the TimeTracker application.
- API Overview
- Authentication & Authorization
- Entry Tracking APIs
- Administrative APIs
- Data Retrieval APIs
- Interpretation & Reporting APIs
- System Status APIs
- Configuration APIs
- Error Handling
- Response Formats
The TimeTracker application provides RESTful endpoints organized by functional domains:
- Entry Tracking:
/tracking/*- Time entry operations - Administration:
/admin/*- Resource management (PL users only) - Data Access:
/get*- Data retrieval operations - Interpretation:
/interpretation/*- Reporting and analysis - Status:
/status/*- System health checks - Configuration:
/settings/*- User preferences
- Request:
application/json(for POST requests with DTOs) - Response:
application/json(standard),text/csv(exports) - Form Data:
application/x-www-form-urlencoded(legacy endpoints)
- Success: JSON with data or confirmation message
- Error: JSON with error message and appropriate HTTP status code
- Pagination: Links object with
first,last,next,prevURLs
- Session-based: Cookie authentication via Symfony Security
- LDAP Integration: Automatic user creation on successful LDAP authentication
- Authenticated User: Access to own data and basic operations
- Project Leader (PL): Administrative access to resource management
- Developer (DEV): Special access permissions for development operations
All endpoints require authentication except:
POST /login- Authentication endpointGET /status/check- Health check (returns login status)
Purpose: Create or update time entries
Authentication: Required
Request Body (EntrySaveDto):
{
"id": null, // Entry ID for updates (null for new)
"date": "2024-09-14", // Date in Y-m-d format (required)
"start": "09:00:00", // Start time in H:i:s format (required)
"end": "17:30:00", // End time in H:i:s format (required)
"ticket": "PROJ-456", // Ticket reference (max 50 chars)
"description": "Work done", // Description (max 1000 chars)
"project_id": 10, // Project ID (required)
"customer_id": 5, // Customer ID (required)
"activity_id": 2, // Activity ID (required)
"extTicket": "EXT-789" // External ticket reference
}Validation Rules:
date,start,endare required- Start time must be before end time
- Ticket format: alphanumeric with hyphens/underscores
- All referenced entities must exist and be active
Response (200 OK):
{
"result": {
"date": "14/09/2024",
"start": "09:00",
"end": "17:30",
"user": 123,
"customer": 5,
"project": 10,
"activity": 2,
"duration": 510, // Duration in minutes
"durationString": "08:30",
"class": "DAYBREAK",
"ticket": "PROJ-456",
"description": "Work done"
}
}Errors:
400 Bad Request: Invalid data, missing required fields, time validation errors401 Unauthorized: Not authenticated500 Internal Server Error: Database operation failed
Purpose: Delete a time entry
Authentication: Required (own entries only)
Request Body (IdDto):
{
"id": 123
}Response (200 OK):
{
"message": "Entry deleted successfully"
}Errors:
400 Bad Request: Entry not found or not owned by user401 Unauthorized: Not authenticated
Purpose: Create multiple time entries from a preset template
Authentication: Required
Request Body (BulkEntryDto):
{
"preset": 5, // Preset template ID (required)
"startdate": "2024-09-01", // Start date for bulk creation
"enddate": "2024-09-30", // End date for bulk creation
"starttime": "08:00:00", // Default start time
"endtime": "16:30:00", // Default end time
"usecontract": 1, // Use contract hours (0/1)
"skipweekend": 1, // Skip weekends (0/1)
"skipholidays": 1 // Skip holidays (0/1)
}Response (200 OK):
25 entries have been addedErrors:
422 Unprocessable Entity: Validation errors, missing preset, no contract found401 Unauthorized: Not authenticated
Note: All administrative endpoints require Project Leader (PL) authorization.
Purpose: Retrieve all customers
Authentication: Required
Response (200 OK):
[
{
"id": 1,
"name": "Customer Name",
"active": true,
"global": false,
"teams": [1, 2, 3]
}
]Purpose: Create or update customer
Authentication: Required (PL only)
Request Body (CustomerSaveDto):
{
"id": 0, // 0 for new customer
"name": "New Customer", // Required, max 100 chars
"active": true, // Required
"global": false, // Required
"teams": [1, 2, 3] // Team IDs (required if not global)
}Validation Rules:
- Non-global customers must belong to at least one team
- Team IDs must exist in database
- Name is required and unique
Response (200 OK):
[1, "New Customer", true, false, [1, 2, 3]]Errors:
403 Forbidden: Not a project leader404 Not Found: Customer not found (for updates)406 Not Acceptable: Validation errors, missing teams
Purpose: Delete customer
Request Body (IdDto):
{
"id": 123
}Response (200 OK):
{
"message": "Customer deleted successfully"
}Purpose: Create or update project
Request Body (ProjectSaveDto):
{
"id": 0,
"name": "New Project", // Required, max 100 chars
"active": true, // Required
"global": false, // Required
"customer_id": 5, // Required, must exist
"jira_id": "PROJ", // Optional, Jira project key
"jira_login": "user@example.com", // Optional
"jira_password": "secret", // Optional
"teams": [1, 2] // Required if not global
}Response (200 OK):
[1, "New Project", true, false, 5, "PROJ", [1, 2]]Purpose: Delete project
Request Body (IdDto)
Purpose: Retrieve all teams
Response (200 OK):
[
{
"id": 1,
"name": "Development Team",
"active": true
}
]Purpose: Create or update team
Request Body (TeamSaveDto):
{
"id": 0,
"name": "New Team", // Required, max 100 chars
"active": true // Required
}Purpose: Delete team
Purpose: Create or update activity
Request Body (ActivitySaveDto):
{
"id": 0,
"name": "Development", // Required, max 100 chars
"factor": 1.0, // Billing factor
"active": true, // Required
"teams": [1, 2] // Team assignments
}Purpose: Delete activity
Purpose: Retrieve all users
Response (200 OK):
[
{
"id": 1,
"username": "john.doe",
"email": "john@example.com",
"type": "DEV", // UserType: DEV, PL
"active": true,
"teams": [1, 2]
}
]Purpose: Create or update user
Request Body (UserSaveDto):
{
"id": 0,
"username": "new.user", // Required, unique
"email": "new@example.com", // Required, valid email
"type": "DEV", // Required: DEV or PL
"active": true, // Required
"teams": [1, 2], // Team assignments
"showFuture": false // Show future dates in UI
}Purpose: Delete user
Purpose: Retrieve all presets for current user
Response (200 OK):
[
{
"id": 1,
"name": "Daily Standup",
"customer_id": 5,
"project_id": 10,
"activity_id": 2,
"description": "Daily standup meeting"
}
]Purpose: Create or update preset template
Request Body (PresetSaveDto):
{
"id": 0,
"name": "Meeting Template", // Required
"customer_id": 5, // Required
"project_id": 10, // Required
"activity_id": 2, // Required
"description": "Template for meetings"
}Purpose: Delete preset
Purpose: Retrieve user contracts
Response (200 OK):
[
{
"id": 1,
"user_id": 123,
"start": "2024-01-01",
"end": "2024-12-31",
"hours0": 0.0, // Sunday hours
"hours1": 8.0, // Monday hours
"hours2": 8.0, // Tuesday hours
"hours3": 8.0, // Wednesday hours
"hours4": 8.0, // Thursday hours
"hours5": 8.0, // Friday hours
"hours6": 0.0 // Saturday hours
}
]Purpose: Create or update contract
Request Body (ContractSaveDto):
{
"id": 0,
"user_id": 123, // Required
"start": "2024-01-01", // Required, date format
"end": "2024-12-31", // Optional, date format
"hours0": 0.0, // Hours for each day of week
"hours1": 8.0,
"hours2": 8.0,
"hours3": 8.0,
"hours4": 8.0,
"hours5": 8.0,
"hours6": 0.0
}Purpose: Delete contract
Purpose: Retrieve configured ticket systems
Response (200 OK):
[
{
"id": 1,
"name": "Jira Production",
"type": "jira",
"url": "https://company.atlassian.net",
"active": true
}
]Purpose: Create or update ticket system
Request Body (TicketSystemSaveDto):
{
"id": 0,
"name": "New Jira Instance", // Required
"type": "jira", // Required
"url": "https://jira.company.com", // Required, valid URL
"active": true // Required
}Purpose: Delete ticket system
Purpose: Synchronize time entries with Jira
Authentication: Required (PL only)
Response (200 OK):
{
"synchronized": 15,
"errors": 2,
"message": "Synchronization completed"
}Purpose: Sync subttickets for all projects
Purpose: Sync subtickers for specific project
Parameters:
project: Project ID
Query Parameters (AdminSyncDto):
project: Project ID to sync
Purpose: Retrieve user's time entries for recent days or filtered data
Authentication: Required
Query Parameters:
days: Number of recent days (default: 3)year: Filter by year (triggers summary mode)month: Filter by month (requires year)user: User ID filter (for PL users, default: 0 = all)customer: Customer ID filterproject: Project ID filter
Response (200 OK) - Recent entries:
[
{
"id": 123,
"date": "2024-09-14",
"start": "09:00:00",
"end": "17:30:00",
"duration": 510,
"customer": "Customer Name",
"project": "Project Name",
"activity": "Development",
"description": "Work description",
"ticket": "PROJ-456"
}
]Response (200 OK) - Filtered summary:
{
"totalWorkTime": 12600 // Total minutes worked
}Purpose: Retrieve entries for specific number of days
Parameters:
days: Number of days to retrieve
Purpose: Retrieve customers accessible to current user
Response (200 OK):
[
{
"id": 1,
"name": "Customer Name",
"projects": [
{
"id": 10,
"name": "Project Name",
"active": true
}
]
}
]Purpose: Retrieve single customer with projects
Query Parameters:
id: Customer ID
Purpose: Retrieve projects accessible to current user
Response (200 OK):
[
{
"id": 10,
"name": "Project Name",
"customer_id": 1,
"customer_name": "Customer Name",
"active": true,
"jira_id": "PROJ"
}
]Purpose: Retrieve all projects (admin view)
Purpose: Retrieve hierarchical customer/project structure
Response (200 OK):
{
"customers": [
{
"id": 1,
"name": "Customer Name",
"projects": [
{
"id": 10,
"name": "Project Name",
"activities": [
{
"id": 2,
"name": "Development"
}
]
}
]
}
]
}Purpose: Retrieve activities accessible to current user
Response (200 OK):
[
{
"id": 1,
"name": "Development",
"factor": 1.0,
"active": true
}
]Purpose: Retrieve users in current user's teams
Response (200 OK):
[
{
"id": 1,
"username": "john.doe",
"email": "john@example.com",
"active": true
}
]Purpose: Retrieve holiday calendar
Response (200 OK):
{
"2024": [
{
"date": "2024-01-01",
"name": "New Year's Day",
"type": "public"
}
]
}Purpose: Generate time summary report
Method: POST (legacy endpoint)
Response (200 OK):
{
"summary": {
"totalHours": 160.5,
"totalMinutes": 9630,
"averageDaily": 8.0,
"workingDays": 20
},
"breakdown": [
{
"customer": "Customer Name",
"project": "Project Name",
"hours": 40.0,
"percentage": 25.0
}
]
}Purpose: Get time summary for current user
Response (200 OK):
{
"today": {
"hours": 8.5,
"minutes": 510
},
"week": {
"hours": 42.0,
"minutes": 2520
},
"month": {
"hours": 168.0,
"minutes": 10080
}
}Purpose: Get time summary for specific ticket
Parameters:
ticket: Ticket identifier (optional)
Response (200 OK):
{
"ticket": "PROJ-456",
"totalTime": 480, // Minutes
"entries": [
{
"date": "2024-09-14",
"duration": 240,
"description": "Implementation work"
}
]
}Purpose: JavaScript integration for Jira time tracking
Response (200 OK):
{
"script": "// JavaScript code for Jira integration",
"version": "1.0.0"
}Note: All interpretation endpoints require Project Leader (PL) authorization.
Purpose: Retrieve paginated entries with filtering
Authentication: Required (PL only)
Query Parameters (InterpretationFiltersDto):
page: Page number (default: 1)limit: Items per page (default: 25, max: 100)year: Year filtermonth: Month filter (1-12)user: User ID filtercustomer: Customer ID filterproject: Project ID filteractivity: Activity ID filterticket: Ticket filterdescription: Description searchstart_date: Start date filter (YYYY-MM-DD)end_date: End date filter (YYYY-MM-DD)
Response (200 OK):
{
"data": [
{
"id": 123,
"date": "2024-09-14",
"user": "john.doe",
"customer": "Customer Name",
"project": "Project Name",
"activity": "Development",
"duration": 480,
"description": "Work description",
"ticket": "PROJ-456"
}
],
"first": "/interpretation/allEntries?page=1",
"last": "/interpretation/allEntries?page=10",
"next": "/interpretation/allEntries?page=3",
"prev": "/interpretation/allEntries?page=1",
"total": 245,
"page": 2,
"limit": 25
}Errors:
400 Bad Request: Invalid page number403 Forbidden: Not a project leader422 Unprocessable Entity: Invalid date format
Purpose: Get recent entries for interpretation
Authentication: Required (PL only)
Query Parameters:
limit: Number of entries (default: 50)
Response (200 OK):
[
{
"id": 123,
"date": "2024-09-14",
"user": "john.doe",
"duration": 480,
"description": "Recent work"
}
]Purpose: Group entries by user
Authentication: Required (PL only)
Query Parameters: Same as allEntries
Response (200 OK):
[
{
"user": "john.doe",
"totalHours": 160.0,
"totalMinutes": 9600,
"entries": 48,
"averageDaily": 8.0
}
]Purpose: Group entries by customer
Response (200 OK):
[
{
"customer": "Customer Name",
"totalHours": 240.0,
"totalMinutes": 14400,
"entries": 72,
"projects": [
{
"project": "Project Name",
"hours": 160.0
}
]
}
]Purpose: Group entries by project
Purpose: Group entries by activity
Purpose: Group entries by ticket
Purpose: Group entries by time periods
Response (200 OK):
[
{
"period": "2024-09",
"totalHours": 168.0,
"workingDays": 21,
"averageDaily": 8.0,
"users": [
{
"user": "john.doe",
"hours": 168.0
}
]
}
]Purpose: Health check and login status
Authentication: Not required
Response (200 OK):
{
"loginStatus": true
}Purpose: Status page with system information
Authentication: Not required
Response (200 OK): HTML status page
Purpose: Save user preferences
Authentication: Required
Request Body:
{
"locale": "en", // Language preference
"showFuture": false, // Show future dates
"theme": "light", // UI theme
"timeFormat": "24h", // Time display format
"dateFormat": "Y-m-d" // Date display format
}Response (200 OK):
{
"message": "Settings saved successfully"
}Purpose: Export time entries as CSV
Authentication: Required
Parameters:
days: Number of days to export (default: 10000)
Response (200 OK): CSV file
Date,Start,End,Duration,Customer,Project,Activity,Description,Ticket
2024-09-14,09:00:00,17:30:00,08:30,Customer Name,Project Name,Development,Work done,PROJ-456Purpose: Administrative export with advanced filtering
Authentication: Required (PL only)
Query Parameters (ExportQueryDto):
userid: User ID filter (0 = all users)year: Year filtermonth: Month filterproject: Project ID filtercustomer: Customer ID filterbillable: Billable filter (0/1)
Response (200 OK): CSV file with administrative data
Purpose: Display login form
Response (200 OK): HTML login page
Purpose: Authenticate user
Form Data:
_username: Username_password: Password
Response:
302 Found: Redirect to dashboard on success200 OK: Login form with error message on failure
Purpose: Logout current user
Response (302 Found): Redirect to login page
Purpose: Handle Jira OAuth callback
Query Parameters:
oauth_token: OAuth tokenoauth_verifier: OAuth verifier
200 OK: Request successful, data returned201 Created: Resource created successfully204 No Content: Request successful, no data returned
400 Bad Request: Invalid request data, validation errors401 Unauthorized: Authentication required403 Forbidden: Access denied, insufficient permissions404 Not Found: Resource not found406 Not Acceptable: Request cannot be processed422 Unprocessable Entity: Validation errors in request payload
500 Internal Server Error: Unexpected server error
{
"error": "Error message",
"code": 400,
"details": {
"field": "Specific field error",
"validation": ["List of validation errors"]
}
}-
Authentication Errors:
- Missing session:
401 Unauthorized - Expired session: Redirect to
/login
- Missing session:
-
Authorization Errors:
- PL permission required:
403 Forbidden - Resource ownership:
403 Forbidden
- PL permission required:
-
Validation Errors:
- Required field missing:
400 Bad Request - Invalid format:
422 Unprocessable Entity - Business rule violation:
406 Not Acceptable
- Required field missing:
-
Resource Errors:
- Entity not found:
404 Not Found - Inactive resource:
400 Bad Request - Constraint violation:
409 Conflict
- Entity not found:
{
"data": {}, // Response payload
"message": "Success", // Optional message
"timestamp": "2024-09-14T10:30:00Z"
}{
"data": [], // Array of items
"total": 245, // Total count
"page": 2, // Current page
"limit": 25, // Items per page
"first": "/endpoint?page=1", // First page URL
"last": "/endpoint?page=10", // Last page URL
"next": "/endpoint?page=3", // Next page URL
"prev": "/endpoint?page=1" // Previous page URL
}[
{
"id": 1,
"name": "Item 1"
},
{
"id": 2,
"name": "Item 2"
}
]For successful operations without data:
{
"message": "Operation completed successfully"
}Currently, the TimeTracker API does not implement rate limiting. However, consider the following recommendations for high-volume usage:
- Bulk Operations: Use
/tracking/bulkentryfor creating multiple entries - Batch Requests: Group related operations when possible
- Pagination: Use appropriate
limitvalues for large datasets - Caching: Implement client-side caching for relatively static data
const response = await fetch('/tracking/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: '2024-09-14',
start: '09:00:00',
end: '17:30:00',
project_id: 10,
customer_id: 5,
activity_id: 2,
description: 'API integration work',
ticket: 'PROJ-456'
})
});
const data = await response.json();const response = await fetch('/getData?days=7');
const entries = await response.json();// Create customer
const customer = await fetch('/customer/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 0,
name: 'New Customer',
active: true,
global: false,
teams: [1, 2]
})
});
// Get interpretation report
const report = await fetch('/interpretation/allEntries?year=2024&month=9');
const reportData = await report.json();This API reference provides comprehensive coverage of all TimeTracker endpoints. For specific implementation details, validation rules, and entity relationships, refer to the DTO Documentation and Controller Index.