Timetracker API

Reads and writes one timesheet, stored as a CSV. Private endpoint — every route except /api/health needs a key.

Send the key as X-API-Key, or as Authorization: Bearer <key>.

Entries

MethodRouteWhat it does
GET/api/entriesList entries. Filters: project, from, to, open, limit.
GET/api/entries/{id}One entry.
POST/api/entriesAdd an entry. Project required, Date defaults to today.
PATCH/api/entries/{id}Change any fields of one entry.
DELETE/api/entries/{id}Delete one entry.

Timer

MethodRouteWhat it does
GET/api/timerThe running entry, if any.
POST/api/timer/startStart on a project. Start time rounds down to the quarter hour.
POST/api/timer/stopClose the running entry. End time rounds up to the quarter hour.

Both accept at (HH:MM) to log a time other than now, and a Description. Starting while one already runs returns 409 unless ?force=true.

Columns

MethodRouteWhat it does
GET/api/columnsList the columns.
POST/api/columnsAdd one: {"name":"Kunde"}, optionally after. Backfills blank on every row.
DELETE/api/columns/{name}Remove one and its data. Needs ?confirm=true.

id can never be deleted. The columns the timer relies on need &force=true as well.

Reading it back

MethodRouteWhat it does
GET/api/summaryHours per project. Same filters as /api/entries.
GET/api/export.csvThe whole sheet as CSV, Excel-safe.
GET/api/export.xlsxFormatted workbook.
GET/api/healthLiveness. No key needed.

Examples

curl -H "X-API-Key: $KEY" https://timetracker.elias-teubner.dev/api/entries

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"Project":"Voice Service Agent"}' \
  https://timetracker.elias-teubner.dev/api/timer/start

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"Description":"Hangup-Problem behoben"}' \
  https://timetracker.elias-teubner.dev/api/timer/stop

curl -H "X-API-Key: $KEY" -o timesheet.xlsx \
  https://timetracker.elias-teubner.dev/api/export.xlsx