One endpoint, every table
Everything the Bilanc dashboard shows is served by a single endpoint. Each metric is an aggregation over one of Bilanc’s modelled tables (pull requests, reviews, issues, CI runs, AI copilot usage, posthook sessions, surveys, and so on). You pick the metric, and optionally the columns to group by, the date column to window on, and the time granularity. Endpoint:POST https://api.bilanc.co/metrics/{metric_type}
Authentication: API key passed directly in the Authorization header (no Bearer prefix). Generate one from the Bilanc dashboard under Settings → API Keys.
group_by, the same endpoint also serves as a row-level export: group a count metric by the table’s primary key and you get one row per record, with whatever columns you ask for. That is how the dashboard renders its own tables and drill-downs. See Exporting Row-Level Data for the pattern, and Posthook Metrics for pulling AI agent sessions, prompts, files and commits.
Request body
Parameters
start_date is required for every metric except users-count and salary. end_date defaults to today. Dates are ISO 8601 (YYYY-MM-DD) and are compared against the column named in date_field.People and org filters apply to every table. Table-specific filters are ignored by tables that don’t have the column.[] (one aggregate row per date bucket).Valid values are any column of the metric’s source table (see the table reference) plus these derived fields, which work for every table:team_id, team_name, department, squad_id, squad_name, squad_level, descendant_squad_id, descendant_squad_name, manager_id, manager_name, manager_email, role, team_names, level, location, pr_author_team_id, pr_author_team_name, issue_author_team_id, issue_author_team_nameAn unknown field returns 400 with the list of valid fields for that metric, so the error message doubles as a column lookup.users-count and salary. Must be a date or timestamp column of the metric’s source table. It drives both the start_date/end_date window and the date_level bucketing. The valid date columns for each table are listed in the table reference. An invalid value returns 400 listing the valid date fields.day, week, month, quarter, year, or hour. Omit to get a single aggregate row per group. When set, the response includes a {date_level}_date column (e.g. week_date) and every bucket in the window is returned, including empty ones. hour returns an hour_of_day column (0–23) and is only supported on single-metric requests.SUM, AVG, MIN or MAX (case-insensitive). Required for value metrics (sizes, durations, tokens, costs, story points, lines). Count and rate metrics ignore it. Metrics that need it are marked in the metric list.0 (no filtering). Useful with row-level exports, e.g. 1 to keep only sessions that produced AI code.true, every metric column is accompanied by a previous_ twin holding the value for the immediately preceding window of the same length. Default false.group_by field. Defaults to the date bucket.ASC or DESC. Default ASC.get-multiple-metrics has no row cap.Response format
The response is a JSON array of rows. Each row has:- A date column.
{date_level}_date(e.g.day_date,month_date) whendate_levelis set,hour_of_dayforhour, ordate_level_not_set: truewhen it isn’t. - One column per
group_byfield, named as requested. - One or more metric columns. The column name depends on the metric (see All metrics). Value metrics prefix the aggregation in lowercase, e.g.
sum_total_tokens,avg_cycle_time. - With
include_previous_period, aprevious_copy of each metric column.
cycle-time, review-time, posthook-active-time, etc.) are returned in seconds. Rates and ratios are 0–1 fractions, not percentages.
Permissions and data scoping
The API key acts as the user who created it. Row-level security is applied server-side on every query, exactly as in the dashboard:salary,pull-requests-costandproductivity-costreturn403unless the org has salary visibility on and the key owner has thecan-view-salariespermission. Thesalaryandpr_costcolumns are silently removed fromgroup_byotherwise.- Survey metrics (
survey-*) return403for keys owned by anyone other than an Owner or Manager. manager_id,manager_nameandmanager_emailare silently removed fromgroup_byfor non-Owner keys.- Posthook install keys (the org-scoped keys used by the
posthookCLI) are write-only and are rejected by this endpoint with403.
Tables and their columns
Each metric reads from exactly one table. Any column below is valid ingroup_by and order_by for the metrics of that table; columns marked with a date type are valid in date_field. Array and JSON columns (team_ids, squad_details, team_manager_details, pr_ai_summary, …) are technically groupable but rarely useful; use the derived join fields instead.
pull_requests — one row per pull request
pull_requests — one row per pull request
pr_merged_at
Date columns: pr_created_at, pr_merged_at, pr_closed_at, first_commit_at, last_commit_at, first_review_at, first_comment_at, first_activity, user_created_datepr_id, pr_number, pr_title, pr_body, pr_url, pr_state, pr_category, pr_ai_summary, repository, repository_url, source, branch_name, destination_branch, head_sha, additions, deletions, changed_files, total_changed_lines, total_reworked_lines, rework_rate, output_estimate, review_rounds_bucket, requested_reviewers_enriched, requested_teams_enriched, coding_time, pickup_time, review_time, total_cycle_time, commit_to_open, open_to_review, review_to_merge, time_to_first_comment, rework, ai_generated_lines, ai_committed_lines, ai_pct_of_code, total_ai_tokens, ai_output_tokens, top_model, pr_cost, cost_per_productivity, salary, user_id, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idspull_request_reviews — one row per review
pull_request_reviews — one row per review
reviewed_at
Date columns: reviewed_at, latest_reviewed_at, pr_created_at, pr_merged_at, pr_closed_atpr_review_id, pr_id, pr_title, pr_state, pull_request_url, html_url, repository, source, state, latest_review_state, changes_requested_count, comments_count, was_approved_by_requested_reviewer, review_rounds_bucket, time_to_first_comment, commit_id, additions, deletions, is_bot, user_login, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_ids, pr_author_user_id, pr_author_merged_user_id, pr_author_propelauth_user_id, pr_author_name, pr_author_team_names, pr_author_team_idspull_request_comments — one row per PR comment
pull_request_comments — one row per PR comment
commented_at
Date columns: commented_atcomment_id, body, commit_id, pull_request_url, html_url, pr_id, pr_title, repository, is_bot, user_login, user_id, merged_user_id, propelauth_user_id, name, location, level, departments, team_names, team_ids, pr_author_user_id, pr_author_merged_user_id, pr_author_propelauth_user_id, pr_author_name, pr_author_team_names, pr_author_team_idspull_request_commits — one row per commit in a PR
pull_request_commits — one row per commit in a PR
committed_at
Date columns: committed_atcommit_id, sha, commit_message, committed_at, additions, deletions, total_changes, html_url, repository, repository_url, pr_id, pr_number, pr_title, pr_url, pr_state, author_id, author_name, merged_user_id, propelauth_user_id, name, location, level, departments, team_names, team_ids, pr_author_user_id, pr_author_merged_user_id, pr_author_propelauth_user_id, pr_author_name, pr_author_team_names, pr_author_team_idspull_request_events — one row per PR lifecycle event
pull_request_events — one row per PR lifecycle event
event_at
Date columns: event_atpr_id, event_type, event_state, event_url, sha, commit_message, additions, deletions, comment_body, pr_url, pr_number, pr_title, pr_state, repository, actor_merged_user_id, actor_name, merged_user_id, propelauth_user_id, name, location, level, departments, team_names, team_ids, pr_author_merged_user_id, pr_author_propelauth_user_id, pr_author_name, pr_author_team_names, pr_author_team_idsissues — one row per issue / ticket
issues — one row per issue / ticket
completed_at
Date columns: created_at, started_at, completed_at, canceled_atissue_id, issue_title, issue_description, issue_url, source, state_name, state_id, state_type, story_points, project_id, project_name, cycle_id, cycle_number, label_ids, label_name, custom_category, branch_name, pr_details, total_cycle_time, pickup_time, creation_to_completion_time, ticket_age, assignee_id, assignee_email, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_ids, creator_id, creator_name, creator_merged_user_id, creator_propelauth_user_id, creator_team_names, creator_team_ids, creator_departmentsissue_comments — one row per issue comment
issue_comments — one row per issue comment
created_at
Date columns: created_at, updated_atissue_comment_id, comment, url, issue_id, issue_title, source, display_name, user_id, user_url, merged_user_id, propelauth_user_id, name, team_names, team_ids, issue_author_merged_user_id, issue_author_propelauth_user_id, issue_author_name, issue_author_team_names, issue_author_team_idsrelease_details — one row per release
release_details — one row per release
release_date
Date columns: release_daterelease_id, version, notes, repository, pull_requests, author_source_user_id, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idsai_copilot — one row per user per day per copilot source
ai_copilot — one row per user per day per copilot source
date
Date columns: datesource, user_id, user_email, is_active, client_version, accepted_lines_added, accepted_lines_deleted, suggested_lines_to_add, suggested_lines_to_delete, total_lines_added, total_lines_deleted, total_accepts, total_rejects, total_applies, total_tabs_accepted, total_tabs_shown, chat_requests, composer_requests, agent_requests, cmd_k_usages, api_key_requests, bug_bot_usages, subscription_included_requests, usage_based_requests, most_used_model, model_provider, apply_most_used_extension, tab_most_used_extension, total_token_usage, total_cost, total_ai_loc, total_lines_changed, pr_count, total_daily_output_estimate, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idsworkflow_runs — one row per CI workflow run
workflow_runs — one row per CI workflow run
run_created_at
Date columns: run_created_at, run_started_at, run_completed_atworkflow_run_id, workflow_id, workflow_name, workflow_state, workflow_path, run_title, run_number, run_attempt, run_status, run_conclusion, run_url, repository, head_branch, head_sha, source, run_duration_s, macos_run_duration_s, windows_run_duration_s, ubuntu_run_duration_s, total_jobs, successful_jobs, failed_jobs, avg_job_duration_ms, jobs_details, total_artifacts, total_artifact_size_bytes, artifacts_details, estimated_workflow_run_cost_usd, credits_used, associated_pull_request_ids, actor_login, actor_type, source_user_id, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idsuser_metrics — one row per person
user_metrics — one row per person
start_date and date_field are not used).
Date columns: last_active_at, user_created_datemerged_user_id, propelauth_user_id, name, main_email, role, location, level, salary, sources, source_types, tenant_seats, number_of_seats_used, departments, team_names, team_idsposthook_sessions — one row per AI agent session
posthook_sessions — one row per AI agent session
date
Date columns: date, started_at, ended_atsession_id, engineer_email, engineer_name, agent_slug, model_slug, model_provider, repo_id, repo_name, remote_url, branch, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, total_tokens, active_minutes, generated_lines, files_edited, committed_lines, commits_contributed, user_id, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idsFull column descriptions on the Posthook Metrics page.posthook_session_messages — one row per prompt or assistant reply
posthook_session_messages — one row per prompt or assistant reply
date
Date columns: date, message_tsmessage_id, session_id, message_seq, role, source, agent_slug, message_text, tool_calls, turn_minutes, engineer_email, merged_user_id, team_names, team_idsposthook_session_files — one row per (session, file)
posthook_session_files — one row per (session, file)
date
Date columns: date, first_edit_ts, last_edit_tssession_id, file_path, edits, lines_generated, lines_committed, commits_touched, engineer_email, merged_user_id, team_names, team_idsposthook_session_commits — one row per (session, commit)
posthook_session_commits — one row per (session, commit)
date
Date columns: date, committed_atsession_id, commit_id, sha, short_sha, branch, message, author_email, lines_added, lines_removed, files_changed, lines_attributed, attribution_source, confidence, files_touched, pr_id, pr_source, pr_title, pr_url, pr_state, engineer_email, merged_user_id, team_names, team_idssurvey_responses — one row per answered question
survey_responses — one row per answered question
final_response_submitted_at
Date columns: final_response_submitted_at, response_created_at, response_updated_at, recipient_final_response_submitted_at, sent_atsurvey_response_id, survey_id, survey_name, template_id, survey_status, survey_question_id, survey_template_question_id, section_id, section_title, section_order, question_order, question_text, response_type, answer, answer_value, answer_comment, answer_other_text, survey_recipient_id, recipient_type, recipient_email, respondent_propelauth_user_id, respondent_email, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idssurvey_recipients — one row per person a survey was sent to
survey_recipients — one row per person a survey was sent to
created_at
Date columns: created_at, sent_at, survey_email_sent_at, final_response_submitted_atsurvey_recipient_id, survey_id, survey_name, template_id, survey_status, recipient_type, recipient_email, merged_user_id, propelauth_user_id, name, role, location, level, departments, team_names, team_idsAll metrics
Agg marks metrics that requireaggregation; the response column then starts with the lowercase aggregation (shown as {agg}). Multi only marks metrics that are accepted by get-multiple-metrics but not as a single metric_type path.
Pull requests (pull_requests)
Reviews, comments, commits, events
Issues
Releases and CI
AI copilots (ai_copilot)
Seat-level usage from Cursor, GitHub Copilot and similar connections.
Posthook (AI agent attribution)
People and surveys
Special metric types
Thesemetric_type values are not table metrics:

