How Do I See Cost per Workflow?

Cost is recorded per job execution, so cost per workflow is a grouping job: price the CI billing rows, attach the workflow from the run id, then sum.

Cost is recorded per job execution, so cost per workflow is a grouping question: take the per-job rows from the CI tab of the Billing report, attach the workflow each row belongs to, and sum the cost column by workflow. Two routes do the attaching: the Jobs section of the same report already aggregates by repository, workflow, and job name, so it tells you which job names a workflow owns, and the API returns billing rows carrying the GitHub Actions run id, which you can filter on directly or resolve to a workflow name.

Answer

The cost fields and the workflow name live in different reports, and that is the whole shape of the problem.

ReportOne row isCost fieldsWorkflow nameExport
Billing, CI tab (GET /reports/billing/ci)one job executionrunner_cost, snapshot_cost, total_cost, billed_time, execution_timeabsent, carries run_id and vcs_job_id insteadCSV button, or format=csv
Jobs (GET /reports/jobs)one repository, workflow, and job name combinationnoneworkflow_name, plus a workflows filterCSV button, or format=csv
Daywise costs (GET /jobs/daywise-costs)one calendar day, whole organizationamount, cumulative_amountabsentJSON

So the recipe is three steps.

  1. Pull CI billing rows for the period. Each row carries repo, job_name, runner_label, billed_time, total_cost, and the workflow run id.
  2. Attach a workflow to each row. The exact join is the run id: the CI billing endpoint documents run_ids as the GitHub Actions workflow run id, and the same id resolves to a workflow name and path through the GitHub REST API (workflow runs, checked on 2026-08-13). The cheaper join is repo plus job_name against the Jobs report, which already knows the workflow for each job name.
  3. Sum total_cost per workflow.

Here is what the result looks like for one repository over a month. The minute counts are an example fleet; every rate comes from the runner catalog on the pricing page, checked on 2026-08-13.

WorkflowJobs in the workflowRunner labelBilled minutesRateCost
ci.ymlunit-tests, lintwarp-ubuntu-latest-x64-4x3,200$0.008/min$25.60
nightly.ymlintegrationwarp-ubuntu-latest-x64-8x1,500$0.016/min$24.00
release.ymlios-buildwarp-macos-latest-arm64-6x900$0.08/min$72.00
Total5,600$121.60

That table is the reason the grouping is worth doing. release.yml holds 16 percent of the billed minutes and carries 59 percent of the cost, because one macOS minute at $0.08 prices the same as ten minutes on warp-ubuntu-latest-x64-4x at $0.008. A per-repository view averages that away. A per-workflow view puts it on the first row you read.

Detail

The fields that carry billed minutes

Each CI billing row separates two time numbers. execution_time is how long the job ran, and billed_time is the figure the charge was computed from and the one to reconcile against an invoice. CI runners are billed on a per-minute basis (pricing page), so summing billed_time per workflow next to total_cost gives you both halves of every per-workflow number: how many minutes the workflow bought, and what those minutes cost at the labels it used.

Cost itself splits into runner_cost and snapshot_cost on the same row, with a snapshot flag marking whether the job restored a snapshot. Keep both columns in the grouping so a workflow that leans on snapshot restores does not read as a runner rate problem.

The Jobs report supplies the other half of the join: one row per repository, workflow, and job name, with run_count, success_rate, and p75 and p90 for duration and queue time. CPU and memory percentiles appear on the same row when CI observability is enabled, which is how you tell a workflow that is expensive from volume apart from one paying for vCPU it never touches. (cloud runners docs), and every platform writes the same row shape, so one grouping covers a mixed fleet rather than needing a separate method per platform.

Doing the grouping through the API

Start with the daily organization total, which is the number your per-workflow sums have to add up to.

curl -sS -G 'https://api.warpbuild.com/api/v1/jobs/daywise-costs' \
  -H 'Authorization: Bearer wkey-xxxx' \
  -H 'Accept: application/json' \
  --data-urlencode 'start_date=2026-08-01T00:00:00Z' \
  --data-urlencode 'end_date=2026-08-13T00:00:00Z'

The response is an array of daily points, each with the day's spend and the running total across the requested range.

[
  { "date": "2026-08-01", "amount": 41.28, "cumulative_amount": 41.28 },
  { "date": "2026-08-02", "amount": 12.04, "cumulative_amount": 53.32 },
  { "date": "2026-08-03", "amount": 96.7, "cumulative_amount": 150.02 }
]

Then pull the rows that carry the join keys. The CI billing endpoint takes the same RFC3339 bounds, pages at up to 200 rows, and accepts run_ids when you already know which runs a workflow produced, which turns "what did last night's release run cost" into one request.

curl -sS -G 'https://api.warpbuild.com/api/v1/reports/billing/ci' \
  -H 'Authorization: Bearer wkey-xxxx' \
  -H 'Accept: application/json' \
  --data-urlencode 'start_date=2026-08-01T00:00:00Z' \
  --data-urlencode 'end_date=2026-08-13T00:00:00Z' \
  --data-urlencode 'repos=acme/api' \
  --data-urlencode 'per_page=200'

Each element of jobs.items carries repo, job_name, runner_label, run_id, vcs_job_id, billed_time, execution_time, runner_cost, snapshot_cost, and total_cost. Group on the workflow you resolved from run_id, sum total_cost, and check the result against the daywise total for the same window before anyone builds a budget on it. The endpoints are annotated alpha and every response carries an X-WarpBuild-API-Stability header (API reference), so pin your script to documented fields and log that header.

The spreadsheet route

Teams that would rather not write the join in code can do it with two downloads. Export the CI billing table to CSV from the download button, export the Jobs table the same way for the same date range, then look up repo plus job_name from the billing sheet against the jobs sheet to add a workflow column and pivot cost on it. Each export contains all rows matching the current filters and sort order rather than the visible page, so the two sheets line up without paging.

One caveat applies to the job-name join. If two workflows in the same repository both define a job called build, the lookup collapses them into one line. Rename the jobs, prefix them per workflow, or fall back to the run id join, which is exact.

What the per-workflow number leaves out

A per-workflow runner total covers runner and snapshot cost. Remote Docker builder sessions bill separately, per session and grouped by profile or architecture, and cache storage and operations bill on a third tab. A workflow that offloads image builds to a builder profile needs those session costs added before its number is comparable to a workflow that builds on the runner.

Nothing else attaches to the total. Pricing is purely usage based (pricing page). There is no base subscription fee, no platform fee, and no seat fee, so the per-workflow figure moves only when minutes, rates, or job counts move, and adding a repository or an engineer changes no line on the invoice. Signup includes $10 free credits, which is enough to run a real workflow on two labels and read the rows before the first bill.

Can I filter the billing report by workflow name?

The CI billing report filters on repository, runner label, stack, job name, and snapshot usage, and the API adds run_ids and vcs_job_ids. There is no workflow filter, so the workflow arrives from the join described above. For the same money cut by machine size instead of by workflow, see cost per runner label.

How do I get cost per workflow into a spreadsheet?

Download the CI billing CSV and the Jobs CSV for the same date range, join them on repository plus job name, and pivot total_cost by workflow. The API takes format=csv on both endpoints when you want the same two files on a schedule. The cost attribution guide covers the job naming and label conventions that keep those pivots stable across repositories.

Do Docker builder sessions show up in the per-workflow number?

No. Docker builder cost is a separate billing tab, billed per session and grouped by profile or architecture. Add those sessions to the workflow total by hand when a workflow builds images remotely, and price them from the builder profiles on the pricing page.

What is the smallest unit worth measuring?

Below the workflow sits the pull request, which is the unit developers actually feel, and the same billing rows group that way through the run id. CI cost per pull request works through that calculation with the rows and the arithmetic written out.

Start from the reports documentation for the dashboard views, price the runner labels your workflows use on the pricing page, and script the exports with the automation documentation.

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.