Which Metrics Does the API Expose for GitHub Actions?
The reports endpoints cover CI billing, Docker builder billing, cache billing, per-job percentiles, and queue timings, in JSON or CSV, from one API key.
Answer
The API exposes the same reporting surface the dashboard renders: CI billing, Docker builder billing, cache billing, a per-job metrics report, and queue timings, served from https://api.warpbuild.com/api/v1 with an API key that starts with wkey- and carries the CI scope.
Every report endpoint takes start_date and end_date as required RFC3339 timestamps, sorts with sort_by and sort_order, pages with page and per_page, and accepts format=csv. The sections below map to the Reports documentation, and full request and response definitions are in the API reference.
| Endpoint | What it returns | Page size |
|---|---|---|
GET /reports/billing/ci | One row per job execution with repo, job_name, runner_label, stack, execution_time, billed_time, runner_cost, snapshot_cost, and total_cost, plus a daily chart and a summary | per_page default 50, max 200 |
GET /reports/billing/docker-builder | One row per builder session with profile, arch, duration, and cost, plus a summary carrying total_cost and total_sessions | per_page default 50, max 200 |
GET /reports/billing/cache | One row per cache billing entry with type, cost, and timestamp, plus a summary splitting storage_cost from operations_cost | per_page default 50, max 200 |
GET /reports/jobs | One row per repository, workflow, and job name with run_count, success_rate, and p75 and p90 for duration, queue time, CPU, and memory | per_page default 10, max 50 |
GET /reports/queue-timings | One row per runner label and stack with run_count, queue_time_p75, and queue_time_p90, plus a daily chart | per_page default 10, max 50 |
GET /jobs/daywise-costs | One row per day with date, amount, and cumulative_amount | Not paginated |
GET /org_metrics/job_runner_recommendations | Jobs whose utilization crossed an upgrade or downgrade threshold, with the workflow, the job, and the recommended change | per_page with page |
Two constraints belong with that table. The CPU and memory percentiles in the jobs report come from runner telemetry, so they require observability to be enabled and show a dash for jobs without it. And every operation in the API is annotated alpha, with an X-WarpBuild-API-Stability header on every response, so pin only to documented behavior and log that header in your client.
Detail
Which report answers which question
- Money by job, repository, or runner label: the CI billing report. Its rows carry
vcs_job_idandrun_id, which are the GitHub Actions job id and workflow run id from the workflow jobs REST API, checked on 2026-08-13, so billing rows join to your own run data by id. - Money for image builds and for cache: the Docker builder and cache billing reports, which are separate because they bill on session duration and on storage plus operations rather than on runner minutes.
- Slow jobs: the jobs report, where
duration_p90besidequeue_time_p90separates a job that got slower from a job that started later. - Waiting jobs: the queue timings report, aggregated per runner label and stack rather than per job.
- Burn against a budget: daywise costs, which is the smallest response of the set and the easiest to graph.
A worked pull of the queue timings report
One request, filtered to stock runner labels and sorted by the p90 column:
curl -sS -G 'https://api.warpbuild.com/api/v1/reports/queue-timings' \
-H 'Authorization: Bearer wkey-xxxx' \
-H 'Accept: application/json' \
--data-urlencode 'start_date=2026-08-04T00:00:00Z' \
--data-urlencode 'end_date=2026-08-11T00:00:00Z' \
--data-urlencode 'categories=stock' \
--data-urlencode 'sort_by=queue_time_p90' \
--data-urlencode 'sort_order=desc' \
--data-urlencode 'per_page=50'The response has four top-level keys: organization_id, chart, table, and available_filters. Read them in that order.
{
"chart": {
"bucket_interval_seconds": 86400,
"daily": [{ "date": "2026-08-04", "job_count": 812, "total_seconds": 9744 }]
},
"table": {
"items": [
{
"runner_label": "warp-ubuntu-latest-x64-8x",
"stack": "hosted-us",
"stack_kind": "warp",
"run_count": 1240,
"queue_time_p75": 9.4,
"queue_time_p90": 21.8
}
],
"page": 1,
"per_page": 50,
"total_pages": 1,
"total_rows": 6
},
"available_filters": {
"runner_labels": ["warp-ubuntu-latest-x64-8x"],
"categories": ["stock", "custom-warp", "custom-byoc"],
"stack_ids": []
}
}chart.daily gives one point per day with date, job_count, and total_seconds, so average wait for a day is total_seconds / job_count. In the point above that is 9744 / 812 = 12.0 seconds. table.items is where the label-level answer lives: queue_time_p75 and queue_time_p90 are per runner label and stack, so a single label with a high p90 next to a healthy fleet points at that label rather than at the platform. stack_kind separates hosted runners from BYOC runners in the same table. Page with table.next until it stops advancing, or ask for format=csv and skip the loop.
Creating the key, and what else it unlocks
Four steps, per the automation documentation:
- Open the API keys page in dashboard settings at
app.warpbuild.com/settings/api-keys. - Create a key and grant the CI scope. The automation documentation recommends granting CI and Cache together when the same key also drives runner and runner image automation.
- Copy the value at creation time. It starts with
wkey-and is displayed once, so write it into your secret manager in the same step. - Send it as
Authorization: Bearer wkey-xxxxwithAccept: application/json.
That same key reaches past reporting. The automation endpoints list stacks at GET /stacks, create and update runner images at /runner-images, and create, list, and delete runners at /runners, which is how teams build a custom image, run a test suite against it, and promote it without a browser. One operational note from those docs: remove unused custom runners, because job pickup times can increase when many runners are present.
Turning the rows into money
The billing reports return cost per row directly, so the arithmetic is only needed when you model a change. Rates are from the pricing page, checked on 2026-08-13, and billing is per minute.
| Runner label | vCPU | RAM | USD per minute |
|---|---|---|---|
warp-ubuntu-latest-x64-4x | 4 | 16 GB | $0.008 |
warp-ubuntu-latest-x64-8x | 8 | 32 GB | $0.016 |
warp-ubuntu-latest-arm64-8x | 8 | 32 GB | $0.012 |
warp-windows-latest-x64-4x | 4 | 16 GB | $0.016 |
Sum billed_time per runner_label from the CI billing report, convert to minutes, and multiply by the rate. A repository with 1,150 billed minutes on warp-ubuntu-latest-x64-8x in a week is 1,150 x $0.016 = $18.40, which should match the sum of total_cost over the same rows.
Related Questions
Which endpoints return GitHub Actions metrics?
Five report endpoints plus two smaller ones: GET /reports/billing/ci, GET /reports/billing/docker-builder, GET /reports/billing/cache, GET /reports/jobs, GET /reports/queue-timings, GET /jobs/daywise-costs, and GET /org_metrics/job_runner_recommendations. All of the report endpoints take start_date and end_date as RFC3339 timestamps and accept format=csv. The request and response shapes are worked through in pulling GitHub Actions metrics through the API, and GitHub Actions observability is the wider view of what the platform reports across an estate.
Which API key scope do these endpoints need?
The CI scope. Create the key on the API keys page in dashboard settings, send it as an Authorization: Bearer header, and store the value at creation time because it is displayed once. The automation documentation recommends granting CI and Cache together when the same key also drives runner and runner image automation.
Can I get the same numbers as CSV?
Yes. Every report endpoint accepts format=csv, and the export carries every row matching the current filters rather than the visible page. JSON responses page instead, with per_page capped at 200 on the three billing reports and 50 on the jobs and queue timings reports. A scheduled pull that writes both formats is the shape of a weekly GitHub Actions health report.
Why are the CPU and memory columns empty?
CPU and memory percentiles in the jobs report come from runner telemetry, so they require observability to be enabled. Jobs without telemetry show a dash for those columns while run_count, success_rate, the duration percentiles, and the queue time percentiles still populate. If you would rather ask these questions in a chat window than in a client, see can an AI agent query my GitHub Actions metrics?.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.