The TimeTracker REST API provides programmatic access to all time tracking, project management, and reporting features. This API is designed for developers who want to integrate TimeTracker with other tools or build custom applications.
https://your-domain.com/api/v1
All API endpoints require authentication using API tokens. API tokens are managed by administrators through the admin dashboard.
-
Log in as an administrator
-
Navigate to Admin > Security & Access > Api-tokens (
/admin/api-tokens) -
Click Create Token
-
Fill in the required information:
- Name: A descriptive name for the token
- Description: Optional description
- User: The user this token will authenticate as
- Scopes: Select the permissions this token should have
- Expires In: Optional expiration period in days
-
Click Create Token
-
Important: Copy the generated token immediately - you won't be able to see it again!
Include your API token in every request using one of these methods:
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
https://your-domain.com/api/v1/projectscurl -H "X-API-Key: YOUR_API_TOKEN" \
https://your-domain.com/api/v1/projectsAPI tokens follow the format: tt_<32_random_characters>
Example: tt_abc123def456ghi789jkl012mno345pq
API tokens use scopes to control access to resources. When creating a token, select the appropriate scopes:
| Scope | Description |
|---|---|
read:projects |
View projects |
write:projects |
Create and update projects |
read:time_entries |
View time entries |
write:time_entries |
Create and update time entries |
read:tasks |
View tasks |
write:tasks |
Create and update tasks |
read:clients |
View clients |
write:clients |
Create and update clients |
read:reports |
View reports and analytics |
read:users |
View user information |
admin:all |
Full administrative access (use with caution) |
Note: For most integrations, you'll want both read and write scopes for the resources you're working with.
List endpoints support pagination to handle large datasets efficiently. For performance and benchmark targets, see PERFORMANCE.md.
page- Page number (default: 1)per_page- Items per page (default: 50, max: 100)
List responses use a resource-named key (e.g. time_entries, projects, clients) plus a top-level pagination object:
{
"time_entries": [...],
"pagination": {
"page": 1,
"per_page": 50,
"total": 150,
"pages": 3,
"has_next": true,
"has_prev": false,
"next_page": 2,
"prev_page": null
}
}All timestamps use ISO 8601 format:
- Date:
YYYY-MM-DD(e.g.,2024-01-15) - DateTime:
YYYY-MM-DDTHH:MM:SSorYYYY-MM-DDTHH:MM:SSZ(e.g.,2024-01-15T14:30:00Z)
200 OK- Request successful201 Created- Resource created successfully400 Bad Request- Invalid input401 Unauthorized- Authentication required or invalid token403 Forbidden- Insufficient permissions (scope issue)404 Not Found- Resource not found500 Internal Server Error- Server error
All error responses (4xx/5xx) include at least error (user-facing message) and message. Optional error_code (e.g. unauthorized, forbidden, not_found, validation_error) allows machine-readable handling. Validation errors include an errors object with field-level messages.
Example (401):
{
"error": "Invalid token",
"message": "The provided API token is invalid or expired",
"error_code": "unauthorized"
}For scope errors (403):
{
"error": "Insufficient permissions",
"message": "This endpoint requires the 'write:projects' scope",
"error_code": "forbidden",
"required_scope": "write:projects",
"available_scopes": ["read:projects", "read:time_entries"]
}For validation errors (400):
{
"error": "Validation failed",
"message": "Validation failed",
"error_code": "validation_error",
"errors": { "name": ["Name is required"], "project_id": ["project_id is required"] }
}GET /api/v1/info
Returns API version and available endpoints. No authentication required.
Response:
{
"api_version": "v1",
"app_version": "1.0.0",
"documentation_url": "/api/docs",
"endpoints": {
"projects": "/api/v1/projects",
"time_entries": "/api/v1/time-entries",
"tasks": "/api/v1/tasks",
"clients": "/api/v1/clients"
}
}GET /api/v1/health
Check if the API is operational. No authentication required.
GET /api/v1/search
Perform a global search across projects, tasks, clients, and time entries.
Required Scope: read:projects
Query Parameters:
q(required) - Search query (minimum 2 characters)limit(optional) - Maximum number of results per category (default: 10, max: 50)types(optional) - Comma-separated list of types to search:project,task,client,entry
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://your-domain.com/api/v1/search?q=website&limit=10"Search by specific types:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://your-domain.com/api/v1/search?q=website&types=project,task"Response:
{
"results": [
{
"type": "project",
"category": "project",
"id": 1,
"title": "Website Redesign",
"description": "Complete website overhaul",
"url": "/projects/1",
"badge": "Project"
},
{
"type": "task",
"category": "task",
"id": 5,
"title": "Update homepage",
"description": "Website Redesign",
"url": "/tasks/5",
"badge": "In Progress"
}
],
"query": "website",
"count": 2
}Search Behavior:
- Projects: Searches in name and description (active projects only)
- Tasks: Searches in name and description (tasks from active projects only)
- Clients: Searches in name, email, and company
- Time Entries: Searches in notes and tags (non-admin users see only their own entries)
Error Responses:
400 Bad Request- Query is too short (less than 2 characters)401 Unauthorized- Missing or invalid API token403 Forbidden- Token lacksread:projectsscope
Note: The legacy endpoint /api/search is also available for session-based authentication (requires login).
GET /api/v1/projects
Required Scope: read:projects
Query Parameters:
status- Filter by status (active,archived,on_hold)client_id- Filter by client IDpage- Page numberper_page- Items per page
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://your-domain.com/api/v1/projects?status=active&per_page=20"Response:
{
"projects": [
{
"id": 1,
"name": "Website Redesign",
"description": "Complete website overhaul",
"client_id": 5,
"hourly_rate": 75.00,
"estimated_hours": 120,
"status": "active",
"created_at": "2024-01-01T10:00:00Z"
}
],
"pagination": {...}
}GET /api/v1/projects/{project_id}
Required Scope: read:projects
POST /api/v1/projects
Required Scope: write:projects
Request Body:
{
"name": "New Project",
"description": "Project description",
"client_id": 5,
"hourly_rate": 75.00,
"estimated_hours": 100,
"status": "active"
}PUT /api/v1/projects/{project_id}
Required Scope: write:projects
DELETE /api/v1/projects/{project_id}
Required Scope: write:projects
Note: This archives the project rather than permanently deleting it.
GET /api/v1/time-entries
Required Scope: read:time_entries
Query Parameters:
project_id- Filter by projectuser_id- Filter by user (admin only)start_date- Filter by start date (ISO format)end_date- Filter by end date (ISO format)billable- Filter by billable status (trueorfalse)include_active- Include active timers (trueorfalse)page- Page numberper_page- Items per page
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://your-domain.com/api/v1/time-entries?project_id=1&start_date=2024-01-01"POST /api/v1/time-entries
Required Scope: write:time_entries
Request Body:
{
"project_id": 1,
"task_id": 5,
"start_time": "2024-01-15T09:00:00Z",
"end_time": "2024-01-15T17:00:00Z",
"notes": "Worked on feature X",
"tags": "development,frontend",
"billable": true
}Note: end_time is optional. Omit it to create an active timer.
PUT /api/v1/time-entries/{entry_id}
Required Scope: write:time_entries
DELETE /api/v1/time-entries/{entry_id}
Required Scope: write:time_entries
GET /api/v1/timer/status
Required Scope: read:time_entries
Returns the current active timer for the authenticated user.
POST /api/v1/timer/start
Required Scope: write:time_entries
Request Body:
{
"project_id": 1,
"task_id": 5
}POST /api/v1/timer/stop
Required Scope: write:time_entries
Stops the active timer for the authenticated user.
GET /api/v1/tasks
Required Scope: read:tasks
Query Parameters:
project_id- Filter by projectstatus- Filter by statuspage- Page numberper_page- Items per page
POST /api/v1/tasks
Required Scope: write:tasks
Request Body:
{
"name": "Implement login feature",
"description": "Add user authentication",
"project_id": 1,
"status": "todo",
"priority": 1
}GET /api/v1/clients
Required Scope: read:clients
POST /api/v1/clients
Required Scope: write:clients
Request Body:
{
"name": "Acme Corp",
"email": "contact@acme.com",
"company": "Acme Corporation",
"phone": "+1-555-0123"
}Inventory endpoints require the inventory module to be enabled (Admin settings). They use read:projects and write:projects scopes.
GET /api/v1/inventory/transfers
Required Scope: read:projects
Query Parameters:
date_from- Filter transfers on or after this date (YYYY-MM-DD)date_to- Filter transfers on or before this date (YYYY-MM-DD)page- Page numberper_page- Items per page (max 100)
Response: transfers (array of transfer objects with reference_id, moved_at, stock_item_id, from_warehouse_id, to_warehouse_id, quantity, notes, movement_ids) and pagination.
POST /api/v1/inventory/transfers
Required Scope: write:projects
Request Body:
{
"stock_item_id": 1,
"from_warehouse_id": 2,
"to_warehouse_id": 3,
"quantity": 10,
"notes": "Optional notes"
}Response: 201 Created with reference_id, transfers (pair of movements), and success message.
GET /api/v1/inventory/transfers/<reference_id>
Required Scope: read:projects
Returns a single transfer (the pair of out/in movements) or 404 if not found.
Required Scope: read:projects for all report endpoints.
-
Valuation:
GET /api/v1/inventory/reports/valuation
Query:warehouse_id,category,currency_code. Returnstotal_value,by_warehouse,by_category,item_details. -
Movement History:
GET /api/v1/inventory/reports/movement-history
Query:date_from,date_to,stock_item_id,warehouse_id,movement_type,page,per_page. Returnsmovementsand optionalpagination. -
Turnover:
GET /api/v1/inventory/reports/turnover
Query:start_date,end_date,item_id. Returnsstart_date,end_date,items(turnover metrics per item). -
Low Stock:
GET /api/v1/inventory/reports/low-stock
Query:warehouse_id(optional). Returnsitems(entries below reorder point withquantity_on_hand,reorder_point,shortfall, etc.).
GET /api/v1/reports/summary
Required Scope: read:reports
Query Parameters:
start_date- Start date (ISO format)end_date- End date (ISO format)project_id- Filter by projectuser_id- Filter by user (admin only)
Response:
{
"summary": {
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z",
"total_hours": 160.5,
"billable_hours": 145.0,
"total_entries": 85,
"by_project": [
{
"project_id": 1,
"project_name": "Website Redesign",
"hours": 85.5,
"entries": 45
}
]
}
}GET /api/v1/users/me
Required Scope: read:users
Returns information about the authenticated user.
For interactive API documentation and testing, visit:
https://your-domain.com/api/docs
This Swagger UI interface allows you to:
- Browse all available endpoints
- Test API calls directly from your browser
- View detailed request/response schemas
- Try out different parameters
import requests
API_TOKEN = "tt_your_token_here"
BASE_URL = "https://your-domain.com/api/v1"
headers = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
}
# List projects
response = requests.get(f"{BASE_URL}/projects", headers=headers)
projects = response.json()
# Create time entry
time_entry = {
"project_id": 1,
"start_time": "2024-01-15T09:00:00Z",
"end_time": "2024-01-15T17:00:00Z",
"notes": "Development work",
"billable": True
}
response = requests.post(f"{BASE_URL}/time-entries", json=time_entry, headers=headers)const axios = require('axios');
const API_TOKEN = 'tt_your_token_here';
const BASE_URL = 'https://your-domain.com/api/v1';
const headers = {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
};
// List projects
axios.get(`${BASE_URL}/projects`, { headers })
.then(response => console.log(response.data))
.catch(error => console.error(error));
// Start timer
axios.post(`${BASE_URL}/timer/start`,
{ project_id: 1, task_id: 5 },
{ headers }
)
.then(response => console.log('Timer started:', response.data))
.catch(error => console.error(error));# List projects
curl -H "Authorization: Bearer tt_your_token_here" \
https://your-domain.com/api/v1/projects
# Create time entry
curl -X POST \
-H "Authorization: Bearer tt_your_token_here" \
-H "Content-Type: application/json" \
-d '{"project_id":1,"start_time":"2024-01-15T09:00:00Z","end_time":"2024-01-15T17:00:00Z"}' \
https://your-domain.com/api/v1/time-entries- Store tokens securely: Never commit tokens to version control
- Use environment variables: Store tokens in environment variables
- Rotate tokens regularly: Create new tokens periodically and delete old ones
- Use minimal scopes: Only grant the permissions needed
- Set expiration dates: Configure tokens to expire when appropriate
- Use pagination: Don't fetch all records at once
- Filter results: Use query parameters to reduce data transfer
- Cache responses: Cache data that doesn't change frequently
- Batch operations: Combine multiple operations when possible
- Check status codes: Always check HTTP status codes
- Handle rate limits: Implement exponential backoff for rate limit errors
- Log errors: Log API errors for debugging
- Validate input: Validate data before sending to API
The API implements rate limiting to ensure fair usage:
- Per-token limits: 100 requests per minute, 1000 requests per hour
- Response headers: Rate limit information is included in response headers
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when the limit resets
When rate limited, you'll receive a 429 Too Many Requests response.
Webhooks are supported for real-time notifications. You can receive notifications when time entries are created/updated, projects change status, tasks are completed, and timer events occur. See Webhooks for setup and event types.
For API support:
- Documentation: This guide and
/api/docs - GitHub Issues: Report bugs and request features
- Community: Join our community forum
- Initial REST API release
- Full CRUD operations for projects, time entries, tasks, and clients
- Token-based authentication with scopes
- Comprehensive filtering and pagination
- Timer control endpoints
- Reporting endpoints
- Interactive Swagger documentation