Tracker Entries and Timers API
Record work, import entries, and control active timers with team-scoped public API v1 operations.
Tracker entries record completed work in seconds. Timer operations create and finish the same entry resource, so a stopped timer appears in ordinary entry queries.
Endpoints
| Method | Endpoint | Scope | Purpose |
|---|---|---|---|
GET | /tracker-entries | tracker-entries.read | List entries in a date range |
POST | /tracker-entries | tracker-entries.write | Create entries for one or more dates |
POST | /tracker-entries/bulk | tracker-entries.write | Import up to 100 entry definitions |
GET | /tracker-entries/{id} | tracker-entries.read | Retrieve one entry |
PATCH | /tracker-entries/{id} | tracker-entries.write | Update an entry |
DELETE | /tracker-entries/{id} | tracker-entries.write | Delete an entry |
POST | /tracker-entries/timer/start | tracker-entries.write | Start a timer |
POST | /tracker-entries/timer/stop | tracker-entries.write | Stop a timer |
GET | /tracker-entries/timer/current | tracker-entries.read | Retrieve the active timer or null |
GET | /tracker-entries/timer/status | tracker-entries.read | Read live elapsed seconds |
Manual Entry Request
Create and update requests use these fields:
| Field | Type | Rules |
|---|---|---|
projectId | UUID | Necessary team-owned tracker project |
assignedId | UUID or null | Team member; omitted or null defaults to the caller on create |
start | ISO 8601 timestamp | Necessary |
stop | ISO 8601 timestamp | Necessary for manual entries |
dates | date array | 1–366 YYYY-MM-DD values |
duration | integer | Whole seconds from 0 to 31,536,000 |
description | string or null | Up to 2,000 characters |
The server stores the duration that you send. It does not recompute the manual-entry duration from start and stop. Keep those values consistent in your integration.
curl --request POST \
--url https://api.eigenn.io/v1/tracker-entries \
--header "Authorization: Bearer $EIGENN_API_TOKEN" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: entry-2026-07-12-design" \
--data '{
"projectId": "b3b6e2c2-1f2a-4e3b-9c1d-2a4b6e2c21f2",
"start": "2026-07-12T09:00:00.000Z",
"stop": "2026-07-12T10:30:00.000Z",
"dates": ["2026-07-12"],
"duration": 5400,
"description": "Invoice workflow design"
}'Creation returns 201 with data. This is an array because one request can expand across many dates.
Bulk Import
POST /tracker-entries/bulk accepts entries with 1–100 manual entry definitions. Each definition creates one stored record for every value in its dates array. Thus the number of returned records can be more than the number of definitions.
Use one idempotency key for one logical import. After a timeout, list the target date range before you send the request again. Thus you do not create duplicate work records with a new key.
Remote-provider synchronization is not available in Eigenn's public REST API. Normalize Harvest, Toggl, Clockify, or another provider in your own server. Then send the completed entries through this bulk endpoint.
List Entries
GET /tracker-entries needs inclusive from and to dates in YYYY-MM-DD format. projectId is optional.
The response contains:
meta.totalDurationin secondsmeta.totalAmountcalculated from project rates- echoed
meta.fromandmeta.to result, an object keyed by entry date
Each entry includes its project, customer summary, assigned user, billing state, rate, currency, timestamps, and duration.
Update an Entry
PATCH /tracker-entries/{id} accepts any non-empty subset of the manual-entry fields. Omitted fields keep their stored values. If you send dates, it must contain exactly one date. A patch updates one stored entry. Use create or bulk create when one definition must expand across many dates.
An active timer does not yet have a complete stop time or duration. Stop the timer before you patch it as a completed manual entry.
Start a Timer
POST /tracker-entries/timer/start needs projectId. Optional fields are assignedId, description, and a custom ISO 8601 start timestamp.
If the selected user already has an active timer, Eigenn stops it before it creates the new one. A timer start returns 201. An active entry has stop: null and duration: null.
{
"projectId": "b3b6e2c2-1f2a-4e3b-9c1d-2a4b6e2c21f2",
"description": "Reconcile July invoices"
}Read Timer State
GET /tracker-entries/timer/current returns { "data": null } when no timer is active. A timer remains discoverable if it crosses midnight.
GET /tracker-entries/timer/status adds:
isRunningcurrentEntryelapsedTimein whole seconds, which Eigenn calculates when it serves the request
Pass assignedId only for a user in the same team.
Stop a Timer
POST /tracker-entries/timer/stop accepts an optional entryId, assignedId, and custom ISO 8601 stop timestamp. Without entryId, Eigenn stops the selected user's current timer. Without assignedId, it uses the authenticated user.
The server calculates the duration from the stored start and the chosen stop timestamp. A stop timestamp earlier than the start is invalid operational data. Do not send it.
Common Errors
| Status | Cause |
|---|---|
401 | Missing or invalid bearer token |
403 | Missing tracker entry scope |
404 | Entry, project, or assignee is outside the team or no longer exists |
409 | Idempotency or current timer state conflict |
422 | Invalid UUID, date, timestamp, limit, or request shape |