Read a workspace monthly invoice report
Read completed team hours, snapshotted billing and pay rates, costs, and profit for one month.
GET /api/v1/reports/monthly-invoice
Required scope: workspace-reports:read
Use a dedicated read-only reporting key to prepare monthly invoices for a workspace. This endpoint reads financial data for every member, rather than only the key owner's time. It does not create or send invoices.
Authentication and access
An owner or admin selects the correct workspace, opens API keys, chooses Workspace invoice reports (read only) under Key access, and creates a named key. Store the key in the integration's secret manager. It has clients:read, projects:read, and workspace-reports:read; no timer or project mutation scopes. Personal keys and existing keys do not gain reporting access.
Every request checks the key's workspace binding, scope, and the owner's current role. A missing scope returns 403 INSUFFICIENT_SCOPE; a contractor or other non-admin returns 403 FORBIDDEN, including after demotion. Revoked keys and removed memberships fail authentication. See authentication and errors and retries.
Request
GET https://www.tracktimer.app/api/v1/reports/monthly-invoice
Send Authorization: Bearer YOUR_API_KEY. Optional query parameters:
- month: YYYY-MM from 2000-01 through 2100-12. Defaults to the previous calendar month in the report timezone, including January's rollover to December.
- timezone: IANA timezone. Defaults to the key owner's saved timezone, then UTC. Use an explicit timezone for a repeatable billing policy.
- clientId: UUID; limit the report to this client in the bound workspace.
- projectId: UUID; limit the report to this project in the bound workspace.
Unknown parameters and invalid values return 400 INVALID_REQUEST. Filters combine with AND. Other-workspace IDs and filters with no matching time return empty rows and zero totals. There is no workspace selector: the key determines the workspace. The response is not paginated or cached. This GET is safe to retry and uses the shared 120-request-per-minute key quota.
Response — 200
{
"workspace": {
"id": "example-workspace",
"name": "Example workspace"
},
"generatedAt": "2026-11-01T15:00:00.000Z",
"currency": "USD",
"period": {
"month": "2026-10",
"timezone": "America/Panama",
"startDate": "2026-10-01",
"endDate": "2026-10-31",
"from": "2026-10-01T05:00:00.000Z",
"to": "2026-11-01T05:00:00.000Z"
},
"rows": [],
"totals": {
"trackedSeconds": 0,
"billableSeconds": 0,
"nonBillableSeconds": 0,
"billableAmount": "0.00",
"cost": "0.00",
"profit": "0.00"
},
"activeTimers": []
}
The period includes from and excludes to. Calendar boundaries respect timezone and DST. Completed entries contribute only seconds overlapping the month; voided entries never contribute. Archived clients/projects and former members' historical entries remain included. Member names use the current display name, then email, then Former member; use stable memberId and projectId values rather than names as identifiers.
Each row represents one project and member and contains:
- clientId, clientName, projectId, projectName, billingMode, memberId, memberName, entryCount.
- trackedSeconds, billableSeconds, nonBillableSeconds: exact integer seconds. Billable time must be marked billable in an hourly project. Fixed-fee and non-billable project time cannot be invoiced as hourly work.
- rates: segments with billable, billableRateCents, payRateCents, and seconds, retaining the entry's snapshotted rates. Multiple rates are not averaged or silently replaced by a current rate.
- billableAmount: billable seconds times the snapshotted billing rate, aggregated exactly then rounded once per member/project to cents, half up.
- cost: all completed tracked seconds times their snapshotted pay rate, including non-billable time; rounded once per member/project to cents, half up.
- profit: the rounded billableAmount minus the rounded cost.
Totals sum those rounded row amounts, rather than rounding a second, unrounded grand total. Monetary values are decimal-dollar strings. Derive decimal hours for display from seconds; never calculate invoice amounts from rounded decimal hours. For an invoice grouped into one project, sum only that project's rows. Retainers, external contractor rates, customer IDs, and invoice numbering belong in your private invoicing workflow.
activeTimers lists overlapping unfinished entries with entryId, projectId, memberId, and startedAt. They are excluded from rows and totals. Reconcile relevant active timers, unexpected billing modes, unknown people, and rate differences before issuing an invoice. A missing row means no completed overlapping time was found, not proof that work was never performed.
The report does not claim that hours have been invoiced or paid, and does not reserve time against other billing systems. Reconcile existing invoices before any external creation. It contains no entry notes or private activity records. Report payloads must remain private; only these generic instructions belong in public documentation.