The pattern
The metrics endpoint aggregates a table. If you group by the table’s primary key, every group contains exactly one record, so the “aggregate” is the record itself. Add the other columns you want togroup_by and you have a row-level export with the same row-level security the dashboard applies.
This is exactly how the Bilanc dashboard renders its own tables, PR drill-downs and the posthook session viewer, so anything you can see in the app you can pull this way.
Three ingredients:
- A count metric for the table (see the table below). Counts don’t need an
aggregation. - The primary key plus the columns you want in
group_by. Any column of the source table is allowed; see Tables and their columns. - A
date_fieldto window on, andstart_date/end_dateto pick the window.
pr_count: 1 here) and, because no date_level was given, date_level_not_set: true. Both can be dropped by your pipeline.
Which metric and key to use per table
Some count metrics carry a definition.
posthook-sessions-count only counts sessions that generated or committed AI code, so sessions with neither show posthook_sessions_count: 0 but are still returned. reviews-count counts distinct PRs, which is 1 per review row anyway. adopted-users counts active users, so inactive seat-days show 0. Set metric_min_value: 1 to keep only rows the dashboard would count, or leave it at 0 to export everything.Paging through large tables
The single-metric endpoint capslimit at 200 rows and has no offset parameter. Two ways to get everything:
- Window by date (single metric)
- Uncapped (get-multiple-metrics)
Shrink the window until each one returns fewer than 200 rows. Daily windows are usually enough; for very busy days add a
member or repositories filter to split further.Child records: fetch by parent id
Detail tables (posthook prompts, files and commits) are usually pulled per parent. Filter on the parent key and drop the date window down to the parent’s date range:pr_ids; for issues use issue_ids; for CI use workflow_run_ids. Full worked examples for the posthook tables are on the Posthook Metrics page.
Incremental sync
The tables have noupdated_at column exposed for change tracking, so the reliable approach is to re-pull a trailing window on each run (for example the last 3 days) and upsert on the primary key. Late-arriving data is common: PRs get merged days after creation, posthook commits are attributed after the session ends, and CI runs complete after they start. Choose the date_field that matches when your downstream cares about the record (e.g. pr_merged_at for merged PRs, date for sessions) and re-pull generously.
Results are cached for five minutes per unique request body, and the underlying tables refresh hourly, so polling more often than hourly returns the same data.
Things to know
- Row-level security applies. A key created by an Engineer exports only that engineer’s rows. Use an Owner’s key for an org-wide export.
team_id/team_name/departmentfan out. A person in two teams produces two rows for the same record. Group byteam_names(the array) instead if you need one row per record with team context.- Durations are seconds and rates are 0–1. Interval columns such as
coding_timecome back as ISO-style strings when placed ingroup_by; the metric versions (cycle-timeetc.) return seconds. - Text columns are safe to request.
pr_body,comment,message_textandcommit_messageare returned in full. - Invalid
group_byfields return a 400 that lists every valid column for the metric’s table. Use it as a live schema lookup.

