API Documentation

📖 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.

HeaderDescription
X-RateLimit-LimitMaximum requests per window (100)
X-RateLimit-RemainingRemaining requests in current window
Retry-AfterSeconds to wait (only on 429 responses)

❌ Error Responses

All errors return consistent JSON:

{
  "error": "Human-readable error message",
  "code": "ERROR_CODE"
}
HTTP StatusCodeDescription
401UNAUTHORIZEDMissing, invalid, or expired token
403FORBIDDENInsufficient permissions
404NOT_FOUNDResource not found
422VALIDATION_ERRORInvalid input data
429RATE_LIMITEDRate limit exceeded
500SERVER_ERRORInternal 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 ParamTypeDescription
pageintPage number (default: 1)
per_pageintResults per page (1–100, default: 50)
fromdateFilter from date (YYYY-MM-DD)
todateFilter to date (YYYY-MM-DD)
user_idintFilter 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.
FieldTypeRequiredDescription
datedateYesEntry date (YYYY-MM-DD)
start_timetimeNoStart time (HH:MM)
end_timetimeNoEnd time (HH:MM)
durationintNoDuration in seconds (auto-calculated from times)
project_idintNoProject ID
client_idintNoClient ID
descriptionstringNoWork description
is_billableboolNoBillable 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.
FieldTypeRequiredDescription
project_idintNoProject ID
client_idintNoClient ID
descriptionstringNoDescription of work
is_billableboolNoBillable (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 ParamTypeDescription
yearintFilter by year (employees only)
statusstringFilter by status: draft, approved, rejected (admin only)
GET /absences/{id}
Get a single absence by ID.
POST /absences
Create a new absence request.
FieldTypeRequiredDescription
absence_type_idintYesAbsence type ID
date_fromdateYesStart date (YYYY-MM-DD)
date_todateYesEnd date (YYYY-MM-DD)
half_dayboolNoHalf-day request
half_day_periodstringNo"am" or "pm"
notestringNoAdditional note
POST /absences/{id}
Update a draft absence.
POST /absences/{id}/delete
Delete a draft absence.

📁 Projects

GET /projects
List all projects (paginated).
Query ParamTypeDescription
active0/1Show only active (default: 1)
pageintPage number
per_pageintResults per page (1–100)

🏢 Clients

GET /clients
List all clients (paginated).
Query ParamTypeDescription
active0/1Show only active (default: 1)
pageintPage number
per_pageintResults per page (1–100)

📊 Reports

GET /reports/summary
Get a monthly/weekly hours summary.
Query ParamTypeDescription
yearintYear (default: current)
monthintMonth 1–12 (default: current)
user_idintUser 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