📖 API Documentation
TimeTrack REST API v1 — Manage time entries, timers, absences, and more.
🔐 Authentication
All API requests require a Bearer token in the Authorization header.
Authorization: Bearer your-api-token-here
Generate tokens from Profile → API Tokens. Tokens are shown once at creation — store them securely.
⏱ Rate Limiting
**100 requests per minute** per API token.
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window (100) |
X-RateLimit-Remaining | Remaining requests in current window |
Retry-After | Seconds to wait (only on 429 responses) |
❌ Error Responses
All errors return consistent JSON:
{
"error": "Human-readable error message",
"code": "ERROR_CODE"
}
| HTTP Status | Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED | Missing, invalid, or expired token |
| 403 | FORBIDDEN | Insufficient permissions |
| 404 | NOT_FOUND | Resource not found |
| 422 | VALIDATION_ERROR | Invalid input data |
| 429 | RATE_LIMITED | Rate limit exceeded |
| 500 | SERVER_ERROR | Internal server error |
🌐 Base URL
/api/v1
All endpoint paths below are relative to this base.
⏰ Time Entries
GET
/time-entries
List time entries (paginated). Admins see all; employees see own.
| Query Param | Type | Description |
|---|---|---|
page | int | Page number (default: 1) |
per_page | int | Results per page (1–100, default: 50) |
from | date | Filter from date (YYYY-MM-DD) |
to | date | Filter to date (YYYY-MM-DD) |
user_id | int | Filter by user (admin/manager only) |
GET
/time-entries/{id}
Get a single time entry by ID.
POST
/time-entries
Create a new time entry. Send JSON body.
| Field | Type | Required | Description |
|---|---|---|---|
date | date | Yes | Entry date (YYYY-MM-DD) |
start_time | time | No | Start time (HH:MM) |
end_time | time | No | End time (HH:MM) |
duration | int | No | Duration in seconds (auto-calculated from times) |
project_id | int | No | Project ID |
client_id | int | No | Client ID |
description | string | No | Work description |
is_billable | bool | No | Billable flag (default: true) |
POST
/time-entries/{id}
Update an existing time entry. Only draft entries are editable.
POST
/time-entries/{id}/delete
Delete a time entry. Only draft entries are deletable.
▶️ Timer
GET
/timer/status
Get the currently running timer (if any). Returns elapsed seconds.
POST
/timer/start
Start a new timer. Stops any currently running timer first.
| Field | Type | Required | Description |
|---|---|---|---|
project_id | int | No | Project ID |
client_id | int | No | Client ID |
description | string | No | Description of work |
is_billable | bool | No | Billable (default: true) |
POST
/timer/stop
Stop the currently running timer. Returns the completed entry.
🌴 Absences
GET
/absences
List absences. Admins see all; employees see own.
| Query Param | Type | Description |
|---|---|---|
year | int | Filter by year (employees only) |
status | string | Filter by status: draft, approved, rejected (admin only) |
GET
/absences/{id}
Get a single absence by ID.
POST
/absences
Create a new absence request.
| Field | Type | Required | Description |
|---|---|---|---|
absence_type_id | int | Yes | Absence type ID |
date_from | date | Yes | Start date (YYYY-MM-DD) |
date_to | date | Yes | End date (YYYY-MM-DD) |
half_day | bool | No | Half-day request |
half_day_period | string | No | "am" or "pm" |
note | string | No | Additional note |
POST
/absences/{id}
Update a draft absence.
POST
/absences/{id}/delete
Delete a draft absence.
📁 Projects
GET
/projects
List all projects (paginated).
| Query Param | Type | Description |
|---|---|---|
active | 0/1 | Show only active (default: 1) |
page | int | Page number |
per_page | int | Results per page (1–100) |
🏢 Clients
GET
/clients
List all clients (paginated).
| Query Param | Type | Description |
|---|---|---|
active | 0/1 | Show only active (default: 1) |
page | int | Page number |
per_page | int | Results per page (1–100) |
📊 Reports
GET
/reports/summary
Get a monthly/weekly hours summary.
| Query Param | Type | Description |
|---|---|---|
year | int | Year (default: current) |
month | int | Month 1–12 (default: current) |
user_id | int | User ID (admin/manager only) |
Example Response
{
"data": {
"year": 2025,
"month": 7,
"user_id": 1,
"total_entries": 42,
"total_seconds": 604800,
"total_hours": 168.0,
"billable_seconds": 504000,
"billable_hours": 140.0,
"non_billable_seconds": 100800,
"approval_status": "submitted",
"current_week": [
{"date": "2025-07-14", "total_seconds": 28800, "entry_count": 3}
]
}
}
💡 Quick Example
# List your time entries curl -H "Authorization: Bearer YOUR_TOKEN" \ https://your-domain/api/v1/time-entries # Create a time entry curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"date":"2025-07-15","start_time":"09:00","end_time":"17:00","description":"Development work"}' \ https://your-domain/api/v1/time-entries # Start a timer curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"project_id":1,"description":"Bug fixing"}' \ https://your-domain/api/v1/timer/start # Stop the timer curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \ https://your-domain/api/v1/timer/stop