AI agents
Bill for the work your agents actually do
An agent can track its own billable time in FlatHours. It authenticates as itself, reports what it did through the API, and the entry lands in the same timesheet a person's work does. Then it goes on the invoice, because delivery is delivery.
Agents are free and unlimited on every plan. They do not consume a seat, because a seat is a person and an agent is not one.
Cost is the small half of the question
Plenty of tools will now tell you what your AI spend was. That answers "what did AI cost me", which is worth knowing and is not the question anyone is actually losing sleep over.
Every agent entry here carries a bill rate as well as a cost. So the number you get is not spend, it is margin:
An illustration of the shape, not a customer's figures. The report is under Reports, AI margin.
Entries logged without a cost are flagged rather than counted as free. Overstating margin is the one direction a report like this must never be wrong in.
What an agent sends
One call, after the work is done. An agent knows the shape of its work only once it has finished, so it is not made to fake a start and a stop.
POST /api/v1/agent/work
Authorization: Bearer <the agent's own token>
{
"path": "/Users/you/code/harbor-studio",
"seconds": 240,
"notes": "Refactored the invoice serialiser",
"cost_cents": 12
}
It knows where it is, so it does not need an id
Send the working directory and the work lands on the right project. An agent reliably knows what folder it is running in and reliably does not know our record ids, so the directory is the easier half of that pair and the one worth building on.
A directory we have not seen before creates a project named after the folder rather than refusing the work. Refusing would put the setup back: make a project, find its id, wire it in, and only then start tracking. Nothing has to be configured for the first call to work.
Deeper folders still count
Work reported from a subfolder belongs to the project registered above it, because an agent sits wherever it happens to be rather than at the root.
The nearest match wins
A package inside a monorepo that has registered itself keeps its own work instead of it rolling up to the umbrella project.
One project across machines
The same checkout on a laptop and on a server maps to the same project, rather than becoming two that each hold half the work.
Still only your account
A path only ever matches directories registered in your own account. An identical path in someone else's is not visible from here.
project_id still works and always will. It is the precise option, not
the easy one, and picking a project by hand should never have been the price of entry.
Send tokens, not arithmetic
An agent can report tokens and a model name instead of a dollar figure, and FlatHours prices it. Every SDK already hands back a usage object; working out what it cost means tracking list prices that move, which is not your job.
{
"path": "/Users/you/code/harbor-studio",
"seconds": 240,
"model": "claude-opus-4-1",
"input_tokens": 100000,
"output_tokens": 20000
}
Prices cover 2,500+ models across 84 providers and refresh daily, so a call made today is priced with today's numbers. Cache reads are charged at the cache rate rather than the input rate, and a model name with a snapshot suffix still prices against its family instead of silently costing nothing.
You can also set the model once on the agent and leave it off the calls. It is chosen from the catalog rather than typed, so the same model cannot end up spelled three ways across three agents and split into three rows on a report.
A call that reports no token counts records no cost, not zero. Saying nothing about tokens is not the same as reporting none, and only one of those is free.
If your agent knows what it was actually charged, send cost_cents
and that wins. A negotiated rate or a batch discount beats a public list price, and we will not
overwrite it.
Price data from MyTokenTracker, used under CC BY 4.0.
It authenticates as itself
An agent has its own token, not a borrowed one, so its work is attributable and revoking it does not lock a person out.
It cannot reach another organization
A project id from someone else's account does not exist from where the agent is standing, so it is refused exactly like a made-up one.
It cannot promote its own work
An agent may mark its work non-billable, but it can never make billable something the project marked otherwise.
Disabling keeps the history
Turning an agent off revokes its tokens immediately and leaves its entries alone, because invoiced work is evidence rather than the agent's property.
What this is not
It is an API, not an integration. FlatHours does not run your agents, watch them, or reach into your provider account to read your spend. Your agent (or the script around it) sends what it did and what it cost, and you decide what to bill for. If you want the cost filled in automatically, you write that part.
Nothing here watches you either. Agent tracking is data coming into your account, not activity monitoring going out of it, and there is still no screen recording on any plan.
The API is on the paid plans, so this needs Solo at $5/month or Team. The agents themselves are unlimited and free at any number, on any plan that has the API.
There are also optional AI features for people, like drafting an invoice summary from tracked time. Those run on your own API key, so nothing is metered and nothing is sent anywhere unless you switch it on.