AuralisDocs
OperationsInbound messages

Read time and todo rollups for the workspace

Time and todo rollups over one window, for one workspace.

/v1/time-tracking/summaryViewer
Operation id
time_tracking_summary
Access
Any workspace role can call this.
GET/v1/time-tracking/summary

Time and todo rollups over one window, for one workspace.

Answers how much time was logged, by whom, on what day and for which team, plus the state of the workspace's todos. since_days is 1 to 180 and defaults to 14.

The groupings all add up. Per agent, per day and per team minutes each sum to total, and billable plus non-billable equals the total at every level. A row whose agent, day or team is unknown is grouped under a null key rather than dropped, which is what keeps the sums honest.

An empty window returns zeroes, never an error and never a missing key.

todos.by_ticket is capped, and by_ticket_limit reports the cap so a caller can tell a short list from a truncated one. No other grouping is capped.

user_id and team_id narrow everything. For todos, user_id reads as the todo's assignee and team_id as the owning ticket's team.

Conservation is the contract (FR-31, AC-35, AC-36). Every grouping is computed from the same filtered row set as total, so per-agent, per-day and per-team minutes each sum to the reported total, and billable plus non-billable equals the level's own total. A row whose agent, day or team is unknown is grouped under a null key rather than dropped. Dropping it is the one thing that would break the sum, and it is what an inner join instead of a LEFT JOIN would quietly do.

Sums are accumulated in bigint. SUM(integer) already returns one; the previous ::int cast narrowed it back down, which is a ceiling nothing hits at 500 tickets and everything hits eventually.

user_id and team_id narrow the window; a filter the endpoint cannot honour is rejected rather than dropped, so a caller never reads unfiltered numbers as though they were filtered. For todos, user_id reads as the todo's assignee and team_id as the owning ticket's team: the same two questions, asked of the other table.

Tenancy: the request is scoped to one workspace, and the credential presented is what selects it. A caller with no membership in that workspace is refused with 404, which is indistinguishable from a workspace that does not exist.

Authorisation: any workspace role, including viewer. Reads are open to every member.

Access: Authorization: Bearer carrying either a realm access token or an API key. A key must hold the helpdesk-ingress:read scope, and the workspace role of the person who owns it must meet the floor above.

Authorization

AuthorizationBearer <token>

A realm-issued access token, presented as Authorization: Bearer <token>. It acts as the person who signed in, and every operation resolves their workspace role live from the membership record.

In: header

Query Parameters

since_days?Since Days
Range1 <= value <= 180
Default14
user_id?string|null
team_id?string|null

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/v1/time-tracking/summary"
{  "since_days": 14,  "total": {    "entries": 42,    "minutes": 1860,    "billable_minutes": 1440,    "non_billable_minutes": 420  },  "by_agent": [    {      "user_id": "3fe98b76-2409-5003-b75a-93e56b450433",      "user_name": "Dana Osei",      "entries": 30,      "minutes": 1320,      "billable_minutes": 1080,      "non_billable_minutes": 240    },    {      "entries": 12,      "minutes": 540,      "billable_minutes": 360,      "non_billable_minutes": 180    }  ],  "by_day": [    {      "day": "2026-08-13",      "minutes": 240,      "billable_minutes": 180,      "non_billable_minutes": 60    },    {      "day": "2026-08-14",      "minutes": 1620,      "billable_minutes": 1260,      "non_billable_minutes": 360    }  ],  "by_team": [    {      "team_id": "d907a188-148a-5522-82a6-55798ccdecb6",      "team_name": "Billing",      "minutes": 1860,      "billable_minutes": 1440,      "non_billable_minutes": 420    }  ],  "todos": {    "total": {      "total": 31,      "open": 9,      "done": 22,      "overdue": 2    },    "by_assignee": [      {        "assignee_id": "3fe98b76-2409-5003-b75a-93e56b450433",        "assignee_name": "Dana Osei",        "total": 31,        "open": 9,        "done": 22,        "overdue": 2      }    ],    "by_ticket": [      {        "ticket_id": "5e8b0c31-7a4d-4f92-b6c8-1d3e2a5f7b90",        "ticket_subject": "Card declined at checkout",        "total": 3,        "open": 1,        "done": 2,        "overdue": 0      }    ],    "by_ticket_limit": 100  }}