API
Track time, log finished work, and read what's unbilled — from scripts and AI agents, over REST or MCP. Built agent-first: JSON everywhere, idempotent operations, scoped tokens.
Authentication
Create a personal access token under Settings → API tokens. Tokens are scoped —
timer starts/stops/reads the timer,
projects:read lists projects,
entries:write logs and updates time entries, and
reports:read reads unbilled totals.
Send it as a Bearer header:
curl -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/timer
Endpoints
/api/v1/timer
scope: timer
Current timer state.
{"running": true, "entry": {"id": 42, "description": "ABC-1 fix login", "project_id": 1, "project_name": "Acme", "started_at": "2026-07-06T20:37:40+00:00", "ended_at": null, "duration_seconds": 918, "is_running": true, "source": "mcp", "agent": "claude-code"}}/api/v1/timer/start
scope: timer
Start a timer. Both fields are optional; any running timer is stopped first — only one timer runs at a time.
Returns 201 with the new entry.
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"description": "ABC-1 fix login", "project_id": 1}' \
https://tallymeter.com/api/v1/timer/start/api/v1/timer/stop
scope: timer
Stop the running timer; returns the stopped entry. Idempotent: if nothing is running you still
get 200 with {"running": false, "stopped": null} —
retries are always safe.
curl -X POST -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/timer/stop/api/v1/projects
scope: projects:read
Your active projects — use their ids as project_id when starting a timer.
{"projects": [{"id": 1, "name": "Acme", "color": "#10b981"}]}/api/v1/entries/{entry}
scope: entries:write
Update an entry's description and/or project in place — running or finished — without touching its
times. Made for the "timer started, described later" flow: no stopping, no splitting. Entries already
billed on an invoice are frozen and return 409.
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"description": "ABC-1 fix login"}' \
https://tallymeter.com/api/v1/entries/42/api/v1/feedback
scope: any token
Feedback channel for agents — a capability you looked for and couldn't find, a bug, confusing docs.
No specific scope required. Optional category (bug,
missing-capability, docs, other) and tool it relates to.
Every report is read.
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"message": "No endpoint to edit an entry.", "category": "missing-capability"}' \
https://tallymeter.com/api/v1/feedbackMCP — plug your agent in directly
Tallymeter is also a native MCP server (Streamable HTTP) at
https://tallymeter.com/mcp,
authenticated with the same Bearer tokens. Beyond the timer and projects it adds
log-time (file finished work after the fact),
update-entry (fix a running or finished entry's
description in place — both need entries:write) and
unbilled-summary (what is ready to invoice, needs
reports:read) — so an agent can do the work,
log the time it spent, and tell you what to bill.
# Claude Code
claude mcp add --transport http tallymeter https://tallymeter.com/mcp \
--header "Authorization: Bearer $TOKEN"
Tools: timer-status, start-timer,
stop-timer, list-projects,
log-time, update-entry,
unbilled-summary,
send-feedback.
Prefer a ready-made setup? The open-source Tallymeter Agent Skill (MIT) teaches Claude Code and compatible harnesses the whole track→log→bill workflow:
git clone https://github.com/mkantautas/tallymeter-skill ~/.claude/skills/tallymeter
Conventions
- API and MCP access is included in every plan (30-day free trial included) — no separate tier. A lapsed plan returns
403with a renewal link; your data stays put. - Every entry records how it was created:
source(web, api or mcp) andagent(the token's name). Give each agent its own named token and a whole fleet's work stays attributable. - Timestamps are ISO-8601 UTC.
- Errors are JSON with a
messagefield — even without anAcceptheader. Validation failures are422with per-fielderrors. - Missing/invalid token →
401; token without the required scope →403. - Rate limit: 120 requests/minute per user.