> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.fullstackplus.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.fullstackplus.ai/_mcp/server.

# Using it for time tracking

The `/api/v1/commits` endpoint takes a time window and a list of projects and
returns what was committed. A summariser turns that into an invoice line.

```bash
curl -H "X-API-Key: $FSP_KEY" \
  "https://api.fullstackplus.ai/api/v1/commits\
?projects=Crocs%20-%20Riverbed,Good%20Sam\
&from=2026-09-09T00:00:00Z&to=2026-09-09T17:00:00Z\
&branches=all"
```

Projects can be given by **id or name** — a timer knows a project by the name a
human typed on it, while ids are what survive a rename, and supporting only one
of those means somebody maintains a mapping by hand.

## Four things that affect what you bill

#### Commits are deduplicated — check \`branches\`, not the count per branch

A commit merged `develop` → `main` exists on both branches. It is returned
**once**, with `branches: ["develop", "main"]` telling you where it landed.

Returned twice it would be an overcharge, and an overcharge nobody can explain
afterwards.

#### Merge commits are included — filter on \`isMerge\`

Release merges like *"chore: merge release v1.0.409 back to develop"* describe no
work. They are included for completeness and flagged `isMerge: true`.

They carry **no `stats`**, because a merge introduces no changes of its own — so
the field is *absent* rather than zero. A summariser must not read that absence
as "0 lines of work".

#### A 200 can still contain a failure — check each project's \`error\`

If one project cannot be read, that project carries an `error` and a count of 0
while every other project still returns its commits. One unreachable machine must
not empty an invoice for the other twenty-nine.

A zero count with an error set is **not** the same as a quiet week. Check the
field before billing.

#### An unknown project name is a 404, not an empty list

A typo that returned nothing would look exactly like no work having been done,
and the invoice would be written for nothing. So a project name the key cannot
resolve fails the whole call and names the offender.

## Getting better summaries

`stats` is on by default and adds files changed, insertions and deletions.
*"Refactored auth, 12 files, +340/−180"* is a far better prompt for a summariser
than a one-line subject alone. Turn it off with `stats=false` when you want speed
over detail.

Each commit also carries its full message `body`, not just the `subject`.