Time Entries API
Track time spent on tickets for billing and reporting.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /time-entries | List time entries |
| POST | /tickets/:ticket_id/time-entries | Log time on ticket |
| GET | /time-entries/:id | Get time entry |
| PATCH | /time-entries/:id | Update time entry |
| DELETE | /time-entries/:id | Delete time entry |
List Time Entries
GET /api/v1/time-entriesQuery Parameters
| Parameter | Type | Description |
|---|---|---|
ticket_id | uuid | Filter by ticket |
user_id | uuid | Filter by team member |
company_id | uuid | Filter by company |
billable | boolean | Filter billable only |
date_from | date | Entries on or after date |
date_to | date | Entries on or before date |
page | integer | Page number |
per_page | integer | Items per page |
Response
{ "data": [ { "id": "entry-uuid", "ticket": { "id": "ticket-uuid", "code": "ACME-42", "subject": "Cannot login" }, "user": { "id": "user-uuid", "name": "Jane Agent" }, "duration_minutes": 45, "description": "Investigated login issue, reset password", "billable": true, "rate": 150.00, "currency": "USD", "amount": 112.50, "date": "2024-01-15", "created_at": "2024-01-15T11:30:00Z" } ], "meta": { "total": 523, "page": 1, "per_page": 20, "totals": { "duration_minutes": 12450, "billable_amount": 31125.00 } }}Log Time
POST /api/v1/tickets/:ticket_id/time-entriesRequest Body
{ "duration_minutes": 45, "description": "Investigated login issue, reset password", "billable": true, "date": "2024-01-15", "rate": 150.00}| Field | Type | Required | Description |
|---|---|---|---|
duration_minutes | integer | Yes | Time in minutes |
description | string | No | Work description |
billable | boolean | No | Billable time (default: true) |
date | date | No | Date of work (default: today) |
rate | decimal | No | Override hourly rate |
Response
{ "data": { "id": "entry-uuid", "ticket": { ... }, "user": { ... }, "duration_minutes": 45, "description": "Investigated login issue, reset password", "billable": true, "rate": 150.00, "currency": "USD", "amount": 112.50, "date": "2024-01-15", "created_at": "2024-01-15T11:30:00Z" }}Rate Calculation
If rate is not provided, it’s determined by:
- Company rate (if ticket has a company with rate set)
- User rate (team member’s default rate)
- Organization default rate
The amount is calculated as:
amount = (duration_minutes / 60) * rateDuration Formats
The API accepts minutes, but you can calculate from various formats:
| Input | Minutes |
|---|---|
| 1 hour | 60 |
| 1h 30m | 90 |
| 1.5 hours | 90 |
| 45 minutes | 45 |
Get Time Entry
GET /api/v1/time-entries/:idReturns full time entry details.
Update Time Entry
PATCH /api/v1/time-entries/:id{ "duration_minutes": 60, "description": "Updated description", "billable": false}Delete Time Entry
DELETE /api/v1/time-entries/:idResponse
204 No ContentTimer (Coming Soon)
Live timer endpoints for real-time tracking:
# Start timerPOST /api/v1/tickets/:ticket_id/timer/start
# Stop timerPOST /api/v1/tickets/:ticket_id/timer/stop
# Get active timerGET /api/v1/timer/activeReporting
Summary by Company
GET /api/v1/time-entries/summary?group_by=company&date_from=2024-01-01&date_to=2024-01-31{ "data": [ { "company": { "id": "...", "name": "Acme Corp" }, "total_minutes": 1250, "billable_minutes": 1100, "total_amount": 2750.00, "currency": "USD" } ]}Summary by User
GET /api/v1/time-entries/summary?group_by=user&date_from=2024-01-01&date_to=2024-01-31Export
GET /api/v1/time-entries/export?format=csv&date_from=2024-01-01&date_to=2024-01-31Returns CSV with columns:
- Date
- Ticket Code
- Ticket Subject
- Company
- User
- Duration
- Description
- Billable
- Rate
- Amount
- Currency
Error Codes
| Code | Description |
|---|---|
TICKET_NOT_FOUND | Ticket doesn’t exist |
TIME_ENTRY_NOT_FOUND | Time entry doesn’t exist |
INVALID_DURATION | Duration must be positive |
UNAUTHORIZED | Can only edit own entries (non-admin) |