# Tallymeter > Tallymeter is a time tracker and invoicer for people and teams that bill for their time. AI agents can use it two ways: a token-authenticated REST API at /api/v1 (timer start/stop/status, entry updates, projects, board remaining work, feedback) and a native MCP server at /mcp (Streamable HTTP) that additionally logs completed work, reports unbilled time and runs the built-in kanban board. The board is the issue tracker the time is logged against: a ticket carries the estimate and the time entries carry the hours, so "how many tickets and hours are left" is one query rather than a reconciliation between two systems. Tracked time can later be turned into client-ready PDF invoices in the web app, and a two-way Jira Cloud sync keeps tracker time and Jira worklogs reconciled ticket by ticket. Authentication: HTTP Bearer with a personal access token (both REST and MCP). A signed-in user creates tokens at Settings → API tokens (https://tallymeter.com/settings). Tokens are scoped — `timer` (start/stop/read the timer), `projects:read` (list projects), `entries:write` (log and update time entries), `reports:read` (unbilled totals), `board:read` (read the board, its tickets and remaining work), `board:write` (create, edit and move tickets). Requests without a valid token get JSON 401; tokens missing the required scope get 403. All timestamps are ISO-8601 UTC. Errors are JSON with a `message` field (and `errors` per field for validation failures). Rate limit: 120 requests/minute per user. Stopping when no timer runs is a success (`{"running": false, "stopped": null}`), so retries are safe. Every entry records its `source` (web/api/mcp) and `agent` (the token's name) — give each agent its own named token and a fleet's work stays attributable per agent. Quick examples: # Read timer state curl -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/timer # Start a timer (project_id optional; starting stops any running timer first) 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 # Stop the running timer (idempotent) curl -X POST -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/timer/stop # Fix an entry's description in place — running or finished (entries:write scope) 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 # Tracked vs unbilled totals for one ticket (reports:read scope) curl -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/tickets/ABC-1/summary # Tickets and hours left on the board (board:read scope) curl -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/board/remaining # A column in rank order — read it before ranking or amending (board:read scope) curl -H "Authorization: Bearer $TOKEN" \ "https://tallymeter.com/api/v1/board/tickets?column=Selected%20for%20Development" # File a ticket; the assigned key comes back (board:write scope) curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"title": "Credit memo moves to the payment area", "column": "Selected for Development", "estimate_minutes": 135, "labels": ["documents"]}' \ https://tallymeter.com/api/v1/board/tickets # Amend a ticket without losing what is there, and rank it (board:write scope) curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"append_description": "## Dependency\n\nBlocked until pricing carries effective dates."}' \ https://tallymeter.com/api/v1/board/tickets/ABC-838 curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"above": "ABC-826"}' https://tallymeter.com/api/v1/board/tickets/ABC-838/move # Who does this token belong to? (any scope) curl -H "Authorization: Bearer $TOKEN" https://tallymeter.com/api/v1/me # File feedback for the developers (any token scope; category: bug|missing-capability|docs|other) curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"message": "I looked for a way to edit an entry but found no endpoint.", "category": "missing-capability"}' \ https://tallymeter.com/api/v1/feedback ## Plans & access Every account starts with a free 30-day trial — no card required, full product including API and MCP access. After the trial a paid subscription is required (€9/month or €90/year); API/MCP access is included in every plan (it is not a separate tier or add-on). When a plan lapses, tokens keep authenticating but every call returns JSON 403 with a renewal link — data is never deleted. Humans sign up at https://tallymeter.com/register and manage the subscription at https://tallymeter.com/billing; tokens are created at https://tallymeter.com/settings. ## MCP server Connect any MCP client (Claude Code, Claude Desktop, Cursor, ...) to https://tallymeter.com/mcp (Streamable HTTP) with the same Bearer token: claude mcp add --transport http tallymeter https://tallymeter.com/mcp --header "Authorization: Bearer $TOKEN" Tools: timer-status, start-timer, stop-timer (idempotent), list-projects, log-time (file a finished piece of work after the fact — description plus either duration_minutes or started_at/ended_at), update-entry (rewrite a running or finished entry's description, project, started_at or ended_at in place — no need to restart the timer; setting ended_at on a running entry finishes it at that moment rather than now; billed entries are frozen), unbilled-summary (finished, not-yet-invoiced time with per-task totals), send-feedback (tell the developers about a missing capability, bug or unclear docs — works with any scope). Board tools: board-remaining (tickets and hours left — estimate minus logged, clamped per ticket, done and backlog columns excluded), list-tickets (a column in rank order before you rank or amend it), create-ticket, update-ticket (`append_description` adds to a body instead of replacing it), move-ticket (rank with `above`, naming the ticket the card should sit on top of, and check the `column_order` it reads back) and comment-ticket. Ticket bodies are markdown. Start a timer with a ticket_id so the time lands on its ticket — that is what keeps remaining work a query. Give every entry a meaningful description (e.g. ticket key + what was done) — undescribed time is never billed. Agent Skill: a ready-made open-source skill (MIT) teaches Claude Code and compatible harnesses this whole track→log→bill workflow, MCP-first with REST fallback. Install: `git clone https://github.com/mkantautas/tallymeter-skill ~/.claude/skills/tallymeter` — source and README at https://github.com/mkantautas/tallymeter-skill. ## API - [OpenAPI specification](https://tallymeter.com/openapi.json): machine-readable spec of every endpoint, schema and error shape - [API documentation](https://tallymeter.com/docs/api): human-readable guide with curl examples ## Product - [Changelog](https://tallymeter.com/changelog): what shipped, when - [Jira sync](https://tallymeter.com/jira): two-way, create-only worklog sync with Jira Cloud - [Try it](https://tallymeter.com/try): guest mode, no account needed ## Support - Email hello@tallymeter.com for support, bug reports or anything else — a human reads and answers every message - Agents: report missing capabilities, bugs or unclear docs directly via the send-feedback MCP tool or POST /api/v1/feedback (works with any token scope) — every report is read