---
title: "Get factory metrics"
method: GET
path: "/factory/{uid}/metrics"
tags: ["Factories", "Metrics"]
---

# Get factory metrics

`GET /factory/{uid}/metrics`

## Request

- Base URL: `https://app.warp.dev/api/v1`
- URL: `https://app.warp.dev/api/v1/factory/{uid}/metrics`
- Auth: HTTP bearer

Aggregate productivity metrics for a factory over a UTC date range:
run count, distinct PR count (from PR artifacts, deduped by URL at
first appearance), autonomy, impact, and PR latency. Cost metrics
live under /factory/{uid}/costs. Pass group_by_period to additionally
receive per-period series aligned to period_list.

## Path parameters

- `uid` string, required

## Query parameters

- `start_date` string, date-time
- `end_date` string, date-time
- `group_by_period` 'day' | 'week' | 'month': Binning granularity for factory metrics series. Weeks start on Sunday (UTC), consistent with existing Warp analytics.

## Response `200`

Factory metrics for the requested range

- FactoryMetricsResponse: Fields every factory-scoped metrics response carries alongside its data, so responses from several factories can be combined or told apart.
  - `as_of` string, date-time, required: The time the data is current as of. Data can lag live activity by a few minutes.
  - `team_uid` string, required: Public UID of the team that owns the factory.
  - `factory_uid` string, required: Public UID of the factory the response is scoped to.
  - `group_by_period` 'day' | 'week' | 'month': Binning granularity for factory metrics series. Weeks start on Sunday (UTC), consistent with existing Warp analytics.
  - `period_list` string[]: Period labels every series aligns to (dates like 2026-07-01; weeks labeled by their Sunday start date). Present only when group_by_period was requested.
  - `data` FactoryMetricsData, required
    - `run_count` FactoryMetricCount, required: A count metric: the aggregate total over the range, plus a per-period series when group_by_period was requested. Grouped breakdowns (drill-down) may be added as new fields in the future.
      - `total` integer, required
      - `series` integer[]: One entry per period_list entry, zero-filled. Present only when group_by_period was requested.
    - `pr_count` FactoryMetricCount, required: A count metric: the aggregate total over the range, plus a per-period series when group_by_period was requested. Grouped breakdowns (drill-down) may be added as new fields in the future.
      - `total` integer, required
      - `series` integer[]: One entry per period_list entry, zero-filled. Present only when group_by_period was requested.
    - `merged_pr_count` FactoryMetricCount, required: A count metric: the aggregate total over the range, plus a per-period series when group_by_period was requested. Grouped breakdowns (drill-down) may be added as new fields in the future.
      - `total` integer, required
      - `series` integer[]: One entry per period_list entry, zero-filled. Present only when group_by_period was requested.
    - `autonomy_funnel` FactoryAutonomyFunnel, required: Autonomy funnel over PRs merged in the range, counted by merge time (merged_at in [start_date, end_date)); merged rows with no recorded merge time are excluded, unlike merged_pr_count's opened-day cohort. total_merged is scoped to the factory's configured repositories while the factory_* stages follow run linkage regardless of repository, so factory_merged can exceed total_merged when a repository was renamed or removed — clients should clamp. Human code-change verdicts are only complete for PRs whose open event was observed (factory_merged_observed); sourced from webhook-collected PR facts, so coverage starts when collection began.
      - `total_merged` integer, required: All merged PRs — human- and agent-authored — in the factory's configured repositories.
      - `factory_merged` integer, required: Merged PRs produced by this factory's runs.
      - `factory_merged_observed` integer, required: factory_merged restricted to PRs whose full history was observed; the autonomy denominator.
      - `merged_without_human_code_change` integer, required: Observed merges where no person changed the code — the autonomy numerator. A person opening the PR or pushing to it is a code change; comments, reviews, and PR actions are not.
      - `repos` string[], required: The repositories total_merged was scoped to, as "owner/repo", deduplicated in configuration order: the factory's configured repositories as of this request, matched against PR facts by their current provider name.
    - `impact` FactoryImpact, required: Lines-changed impact of the factory's PRs merged in the range, counted by merge time like autonomy_funnel; merged rows with no recorded merge time are excluded. Line counts are snapshotted from webhook payloads and can be unobserved, so additions/deletions sum only the measured_pr_count PRs where both were recorded.
      - `additions` integer, required: Lines added across the measured merged PRs.
      - `deletions` integer, required: Lines deleted across the measured merged PRs.
      - `merged_pr_count` integer, required: PRs produced by this factory's runs and merged in the range.
      - `measured_pr_count` integer, required: merged_pr_count restricted to PRs whose line counts were observed; the denominator for additions/deletions.
    - `pr_latency` FactoryPRLatency, required: Median PR throughput/latency pipeline stages over the factory's PRs merged in the range, counted by merge time like autonomy_funnel; kickoff is the creation time of the earliest of the factory's runs linked to the PR (measured from the subrun when only a subrun reported it). First review is the earliest observed HUMAN review event with a recorded time — any review state qualifies except bot reviews and GitHub App reviews (agent reviewers, CI) — so review-anchored stages can be empty when the provider's review webhooks are absent. Every stage is computed independently over the PRs where both endpoints were observed, so stage medians do not sum to kickoff_to_merge's median.
      - `merged_pr_count` integer, required: PRs produced by this factory's runs and merged in the range.
      - `kickoff_to_pr` FactoryLatencyStage, required: One stage of the PR latency pipeline: the median duration across the PRs where both of the stage's endpoints were observed, plus how many PRs that was.
        - `median_seconds` number, double, nullable, required: p50 stage duration in seconds; null when measured_pr_count is zero. Durations are clamped at zero, so out-of-order provider timestamps never produce negative values.
        - `measured_pr_count` integer, required: PRs with both stage endpoints observed.
      - `pr_to_first_review` FactoryLatencyStage, required: One stage of the PR latency pipeline: the median duration across the PRs where both of the stage's endpoints were observed, plus how many PRs that was.
        - `median_seconds` number, double, nullable, required: p50 stage duration in seconds; null when measured_pr_count is zero. Durations are clamped at zero, so out-of-order provider timestamps never produce negative values.
        - `measured_pr_count` integer, required: PRs with both stage endpoints observed.
      - `first_review_to_merge` FactoryLatencyStage, required: One stage of the PR latency pipeline: the median duration across the PRs where both of the stage's endpoints were observed, plus how many PRs that was.
        - `median_seconds` number, double, nullable, required: p50 stage duration in seconds; null when measured_pr_count is zero. Durations are clamped at zero, so out-of-order provider timestamps never produce negative values.
        - `measured_pr_count` integer, required: PRs with both stage endpoints observed.
      - `kickoff_to_merge` FactoryLatencyStage, required: One stage of the PR latency pipeline: the median duration across the PRs where both of the stage's endpoints were observed, plus how many PRs that was.
        - `median_seconds` number, double, nullable, required: p50 stage duration in seconds; null when measured_pr_count is zero. Durations are clamped at zero, so out-of-order provider timestamps never produce negative values.
        - `measured_pr_count` integer, required: PRs with both stage endpoints observed.
    - `average_human_interactions_per_pr` FactoryAverageMetric, required: An average-valued metric: the aggregate average over the range, plus a per-period series when group_by_period was requested. The aggregate and periods with no qualifying PRs read zero.
      - `average` number, double, required: Average value over the range; zero when no PRs qualified.
      - `series` number[]: One entry per period_list entry, zero-filled. Present only when group_by_period was requested.

## Other responses

- `400`: Invalid date range or group_by_period, or more than 365 periods requested
- `401`: Authentication required
- `403`: Factory access is not enabled for the authenticated principal
- `404`: Factory not found or not accessible
- `429`: The caller has used up the request budget shared by the factory metrics endpoints. Wait the number of seconds in Retry-After, then retry.
- `500`: Internal server error

## Changes

- **2026-10-21** `7ee3ba55debc`: 2 info
  - api tag `factory-metrics` added
  - api tag `factory` removed
- **2026-10-15** `f4630aae17ba`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/warp/apis/oz-agent-api/changes/factory/:uid/metrics/get.md)

---

[API](https://skmtc.dev/warp/apis/oz-agent-api.md) - [All operations](https://skmtc.dev/warp/apis/oz-agent-api/llms.txt) - [OpenAPI document](https://skmtc.dev/warp/apis/oz-agent-api/revisions/4b5d145669be?raw)
