Engineering

For instructions on how to authenticate to use this endpoint, see API overview.

Endpoints

GET
GET
GET
GET
GET
GET
GET
GET
GET
GET

Retrieve engineering analytics ci timing

How long a selected workflow, matrix, job or step usually takes: compares it with runs of the same workflow on the repository's default branch over the last 7 days, from stored data only. A run counts only when it ran the same jobs on the same runner tiers, so the answer never mixes in a different workflow, job or runner. Pull request runs and merge queue runs are left out. At most the newest 40 default-branch runs are checked, and sampled is true when more existed. average_seconds and sample_count cover successful samples only, and recent lists the newest three matches of any status. average_seconds is null when no comparable run exists. unavailable_reason says why no comparison was made. Answers are cached for 5 minutes.

Required API key scopes

engineering_analytics:read

Query parameters

  • ci_engine
    string
    One of: "github_actions""depot_ci"
  • job_ids
    string
  • kind
    string
    One of: "workflow""matrix""job""step"
  • repo
    string
  • run_attempt
    integer
  • run_id
    integer
  • source_id
    string
  • step_number
    integer

Response


Example request

GET /api/projects/:project_id/engineering_analytics/ci_timing_context
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/ci_timing_context/

Example response

Status 200
RESPONSE
{
"recent": [
{
"run_id": 0,
"run_attempt": 0,
"job_id": 0,
"step_number": 0,
"ci_engine": "github_actions",
"native_run_id": "string",
"native_workflow_run_id": "string",
"native_job_id": "string",
"native_attempt_id": "string",
"status": "success",
"duration_seconds": 0.1,
"completed_at": "2019-08-24T14:15:22Z",
"head_sha": "string"
}
],
"default_branch": "string",
"window_days": 0,
"identity": "workflow_id",
"runs_scanned": 0,
"sampled": true,
"sample_count": 0,
"average_seconds": 0,
"runs_synced_at": "2019-08-24T14:15:22Z",
"jobs_synced_at": "2019-08-24T14:15:22Z",
"unavailable_reason": "default_branch_unknown"
}
Status 400 Missing or invalid parameters, a run the source does not hold, a job id that is not in the run attempt, or a step number the job does not have.

Retrieve engineering analytics ci timing

How long a selected workflow, matrix, job or step usually takes: compares it with runs of the same workflow on the repository's default branch over the last 7 days, from stored data only. A run counts only when it ran the same jobs on the same runner tiers, so the answer never mixes in a different workflow, job or runner. Pull request runs and merge queue runs are left out. At most the newest 40 default-branch runs are checked, and sampled is true when more existed. average_seconds and sample_count cover successful samples only, and recent lists the newest three matches of any status. average_seconds is null when no comparable run exists. unavailable_reason says why no comparison was made. Answers are cached for 5 minutes.

Required API key scopes

engineering_analytics:read

Query parameters

  • ci_engine
    string
    One of: "github_actions""depot_ci"
  • job_ids
    string
  • kind
    string
    One of: "workflow""matrix""job""step"
  • repo
    string
  • run_attempt
    integer
  • run_id
    integer
  • source_id
    string
  • step_number
    integer

Response


Example request

GET /api/projects/:project_id/engineering_analytics/ci_timing_context
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/ci_timing_context/

Example response

Status 200
RESPONSE
{
"recent": [
{
"run_id": 0,
"run_attempt": 0,
"job_id": 0,
"step_number": 0,
"ci_engine": "github_actions",
"native_run_id": "string",
"native_workflow_run_id": "string",
"native_job_id": "string",
"native_attempt_id": "string",
"status": "success",
"duration_seconds": 0.1,
"completed_at": "2019-08-24T14:15:22Z",
"head_sha": "string"
}
],
"default_branch": "string",
"window_days": 0,
"identity": "workflow_id",
"runs_scanned": 0,
"sampled": true,
"sample_count": 0,
"average_seconds": 0,
"runs_synced_at": "2019-08-24T14:15:22Z",
"jobs_synced_at": "2019-08-24T14:15:22Z",
"unavailable_reason": "default_branch_unknown"
}
Status 400 Missing or invalid parameters, a run the source does not hold, a job id that is not in the run attempt, or a step number the job does not have.

Retrieve engineering analytics current branch

Current default-branch CI verdict over the fixed last-24-hours window. Counts every workflow whose latest completed run failed or timed out; failing workflow names are a bounded preview. The default branch is detected from the same window, independently of analytics date filters.

Required API key scopes

engineering_analytics:read

Query parameters

  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/current_branch_health
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/current_branch_health/

Example response

Status 200
RESPONSE
{
"default_branch": "string",
"settled_workflows": 0,
"failing_workflows": 0,
"failing_workflow_names": [
"string"
]
}
Status 400 Invalid source_id.

Retrieve engineering analytics current branch

Current default-branch CI verdict over the fixed last-24-hours window. Counts every workflow whose latest completed run failed or timed out; failing workflow names are a bounded preview. The default branch is detected from the same window, independently of analytics date filters.

Required API key scopes

engineering_analytics:read

Query parameters

  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/current_branch_health
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/current_branch_health/

Example response

Status 200
RESPONSE
{
"default_branch": "string",
"settled_workflows": 0,
"failing_workflows": 0,
"failing_workflow_names": [
"string"
]
}
Status 400 Invalid source_id.

Retrieve engineering analytics delivery

One author's median ready to merged time, split at the first approval, next to the same medians for the author's own team and for the whole repository, over pull requests merged in the window (date_from default -30d). The team is picked from the author's GitHub teams that own code: a team that pr_number asked to review, else the team the author's pull requests asked to review most often, else every team. Bots and drafts are excluded.

Required API key scopes

engineering_analytics:read

Query parameters

  • author
    string
  • date_from
    string
  • date_to
    string
  • pr_number
    integer
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/delivery_comparison
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/delivery_comparison/

Example response

Status 200
RESPONSE
{
"author_medians": {
"merged_pr_count": 0,
"ready_to_merge_seconds": 0,
"p90_ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"teams": [
{
"medians": {
"merged_pr_count": 0,
"ready_to_merge_seconds": 0,
"p90_ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"github_team": "string"
}
],
"repo_medians": {
"merged_pr_count": 0,
"ready_to_merge_seconds": 0,
"p90_ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"pull_request": {
"number": 0,
"ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"author": "string",
"has_membership_data": true,
"review_data_available": true,
"ready_data_available": true,
"team_basis": "pull_request"
}
Status 400 Missing author, or invalid pr_number, date or source_id.

Retrieve engineering analytics delivery

One author's median ready to merged time, split at the first approval, next to the same medians for the author's own team and for the whole repository, over pull requests merged in the window (date_from default -30d). The team is picked from the author's GitHub teams that own code: a team that pr_number asked to review, else the team the author's pull requests asked to review most often, else every team. Bots and drafts are excluded.

Required API key scopes

engineering_analytics:read

Query parameters

  • author
    string
  • date_from
    string
  • date_to
    string
  • pr_number
    integer
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/delivery_comparison
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/delivery_comparison/

Example response

Status 200
RESPONSE
{
"author_medians": {
"merged_pr_count": 0,
"ready_to_merge_seconds": 0,
"p90_ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"teams": [
{
"medians": {
"merged_pr_count": 0,
"ready_to_merge_seconds": 0,
"p90_ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"github_team": "string"
}
],
"repo_medians": {
"merged_pr_count": 0,
"ready_to_merge_seconds": 0,
"p90_ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"pull_request": {
"number": 0,
"ready_to_merge_seconds": 0,
"ready_to_first_approval_seconds": 0,
"first_approval_to_merge_seconds": 0,
"before_first_approval_share": 0
},
"author": "string",
"has_membership_data": true,
"review_data_available": true,
"ready_data_available": true,
"team_basis": "pull_request"
}
Status 400 Missing author, or invalid pr_number, date or source_id.

Retrieve engineering analytics delivery

Delivery and CI friction for one author or one GitHub team over a window (date_from default -30d), each figure next to the same figure over the whole repository: CI spend per merged PR, ready to merged split at the first approval, pushes after approval, merge-queue attempts, and lead time to deploy. Bots and drafts are excluded. Figures whose optional source isn't synced are null and flagged.

Required API key scopes

engineering_analytics:read

Query parameters

  • author
    string
  • date_from
    string
  • date_to
    string
  • github_team
    string
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/delivery_summary
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/delivery_summary/

Example response

Status 200
RESPONSE
{
"cost_per_merged_pr_usd": {
"scope": 0,
"repo": 0
},
"billable_minutes_per_merged_pr": {
"scope": 0,
"repo": 0
},
"cost_per_push_usd": {
"scope": 0,
"repo": 0
},
"median_ready_to_merge_seconds": {
"scope": 0,
"repo": 0
},
"p90_ready_to_merge_seconds": {
"scope": 0,
"repo": 0
},
"median_ready_to_first_approval_seconds": {
"scope": 0,
"repo": 0
},
"median_first_approval_to_merge_seconds": {
"scope": 0,
"repo": 0
},
"before_first_approval_share": {
"scope": 0,
"repo": 0
},
"pushes_after_approval_per_merged_pr": {
"scope": 0,
"repo": 0
},
"merge_queue_attempts_per_merged_pr": {
"scope": 0,
"repo": 0
},
"failed_merge_queue_share": {
"scope": 0,
"repo": 0
},
"lead_time": {
"open_to_deploy": {
"scope": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
},
"repo": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
},
"open_to_merge": {
"scope": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
},
"repo": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
},
"merge_to_deploy": {
"scope": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
},
"repo": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
},
"deploy_data_available": true,
"environment_scope": "string",
"merged_pr_count": 0,
"deployed_merged_pr_count": 0
},
"scope_kind": "author",
"scope": "string",
"has_membership_data": true,
"jobs_available": true,
"review_data_available": true,
"ready_data_available": true,
"opened_pr_count": 0,
"merged_pr_count": 0,
"open_pr_count": 0,
"draft_pr_count": 0,
"total_cost_usd": 0,
"total_billable_minutes": 0,
"push_count": 0
}
Status 400 Not exactly one of author or github_team, or invalid date or source_id.

Retrieve engineering analytics delivery

Delivery and CI friction for one author or one GitHub team over a window (date_from default -30d), each figure next to the same figure over the whole repository: CI spend per merged PR, ready to merged split at the first approval, pushes after approval, merge-queue attempts, and lead time to deploy. Bots and drafts are excluded. Figures whose optional source isn't synced are null and flagged.

Required API key scopes

engineering_analytics:read

Query parameters

  • author
    string
  • date_from
    string
  • date_to
    string
  • github_team
    string
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/delivery_summary
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/delivery_summary/

Example response

Status 200
RESPONSE
{
"cost_per_merged_pr_usd": {
"scope": 0,
"repo": 0
},
"billable_minutes_per_merged_pr": {
"scope": 0,
"repo": 0
},
"cost_per_push_usd": {
"scope": 0,
"repo": 0
},
"median_ready_to_merge_seconds": {
"scope": 0,
"repo": 0
},
"p90_ready_to_merge_seconds": {
"scope": 0,
"repo": 0
},
"median_ready_to_first_approval_seconds": {
"scope": 0,
"repo": 0
},
"median_first_approval_to_merge_seconds": {
"scope": 0,
"repo": 0
},
"before_first_approval_share": {
"scope": 0,
"repo": 0
},
"pushes_after_approval_per_merged_pr": {
"scope": 0,
"repo": 0
},
"merge_queue_attempts_per_merged_pr": {
"scope": 0,
"repo": 0
},
"failed_merge_queue_share": {
"scope": 0,
"repo": 0
},
"lead_time": {
"open_to_deploy": {
"scope": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
},
"repo": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
},
"open_to_merge": {
"scope": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
},
"repo": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
},
"merge_to_deploy": {
"scope": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
},
"repo": {
"pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
},
"deploy_data_available": true,
"environment_scope": "string",
"merged_pr_count": 0,
"deployed_merged_pr_count": 0
},
"scope_kind": "author",
"scope": "string",
"has_membership_data": true,
"jobs_available": true,
"review_data_available": true,
"ready_data_available": true,
"opened_pr_count": 0,
"merged_pr_count": 0,
"open_pr_count": 0,
"draft_pr_count": 0,
"total_cost_usd": 0,
"total_billable_minutes": 0,
"push_count": 0
}
Status 400 Not exactly one of author or github_team, or invalid date or source_id.

Retrieve engineering analytics

DORA-style deploy metrics over the GitHub deployments + deployment_statuses warehouse pair, each headline with its previous-window twin: deployment frequency, merge-to-deploy lead time (with a per-bucket box-plot series), and honest proxies for change failure rate and time to restore (deploy-status based: no incident data is linked). deploy_data_available is false when the deploy tables aren't synced.

Required API key scopes

engineering_analytics:read

Query parameters

  • date_from
    string
  • date_to
    string
  • environment
    array
  • github_team
    string
  • granularity
    string
    One of: "day""hour""week"
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/dora
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/dora/

Example response

Status 200
RESPONSE
{
"deployment_frequency_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployment_count": 0
}
],
"merge_to_deploy_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployed_pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
],
"open_to_merge_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployed_pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
],
"open_to_deploy_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployed_pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
],
"deploy_data_available": true,
"environment_scope": "string",
"environments": [
"string"
],
"selected_environments": [
"string"
],
"has_membership_data": true,
"github_teams": [
"string"
],
"deployment_count": 0,
"deployment_count_prev": 0,
"deployments_per_day": 0,
"deployments_per_day_prev": 0,
"median_merge_to_deploy_seconds": 0,
"median_merge_to_deploy_seconds_prev": 0,
"median_open_to_deploy_seconds": 0,
"median_open_to_deploy_seconds_prev": 0,
"deployed_pr_count": 0,
"deployed_pr_count_prev": 0,
"failed_deployment_count": 0,
"failed_deployment_count_prev": 0,
"failed_deployment_share": 0,
"failed_deployment_share_prev": 0,
"median_failed_deploy_to_next_success_seconds": 0,
"median_failed_deploy_to_next_success_seconds_prev": 0,
"merged_pr_count": 0,
"unattributed_merged_pr_share": 0,
"latest_deploy_status_at": "2019-08-24T14:15:22Z",
"series_granularity": "string"
}
Status 400 Invalid environment, date_from, date_to, granularity, or source_id.

Retrieve engineering analytics

DORA-style deploy metrics over the GitHub deployments + deployment_statuses warehouse pair, each headline with its previous-window twin: deployment frequency, merge-to-deploy lead time (with a per-bucket box-plot series), and honest proxies for change failure rate and time to restore (deploy-status based: no incident data is linked). deploy_data_available is false when the deploy tables aren't synced.

Required API key scopes

engineering_analytics:read

Query parameters

  • date_from
    string
  • date_to
    string
  • environment
    array
  • github_team
    string
  • granularity
    string
    One of: "day""hour""week"
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/dora
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/dora/

Example response

Status 200
RESPONSE
{
"deployment_frequency_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployment_count": 0
}
],
"merge_to_deploy_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployed_pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
],
"open_to_merge_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployed_pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
],
"open_to_deploy_series": [
{
"bucket_start": "2019-08-24T14:15:22Z",
"deployed_pr_count": 0,
"min_seconds": 0,
"p05_seconds": 0,
"p25_seconds": 0,
"p50_seconds": 0,
"mean_seconds": 0,
"p75_seconds": 0,
"p95_seconds": 0,
"max_seconds": 0
}
],
"deploy_data_available": true,
"environment_scope": "string",
"environments": [
"string"
],
"selected_environments": [
"string"
],
"has_membership_data": true,
"github_teams": [
"string"
],
"deployment_count": 0,
"deployment_count_prev": 0,
"deployments_per_day": 0,
"deployments_per_day_prev": 0,
"median_merge_to_deploy_seconds": 0,
"median_merge_to_deploy_seconds_prev": 0,
"median_open_to_deploy_seconds": 0,
"median_open_to_deploy_seconds_prev": 0,
"deployed_pr_count": 0,
"deployed_pr_count_prev": 0,
"failed_deployment_count": 0,
"failed_deployment_count_prev": 0,
"failed_deployment_share": 0,
"failed_deployment_share_prev": 0,
"median_failed_deploy_to_next_success_seconds": 0,
"median_failed_deploy_to_next_success_seconds_prev": 0,
"merged_pr_count": 0,
"unattributed_merged_pr_share": 0,
"latest_deploy_status_at": "2019-08-24T14:15:22Z",
"series_granularity": "string"
}
Status 400 Invalid environment, date_from, date_to, granularity, or source_id.

Retrieve engineering analytics flaky

The active test-health queue: pytest and Jest tests worth acting on now, from the per-test CI spans, over a window (default -7d, maximum 30 days). Evidence is counted per CI run, never per span or run attempt. A test is a 'confirmed_flake' when one commit both failed and passed it (a 'Re-run failed jobs' attempt went green, or an in-job retry recovered it); 'quarantined' when a tolerated failure is recorded while it is masked; otherwise 'suspected_regression'. It qualifies on any same-commit recovery, any master/main failure, a quarantined failure, or failures on at least min_failed_prs distinct PRs. Counts are absolute, never rates: CI emits every failure but omits ordinary passing spans, so there is no execution denominator. 'suspected_regression' means no recovery was recorded in this data, not that the test never flakes.

Required API key scopes

engineering_analytics:read

Query parameters

  • date_from
    string
  • date_to
    string
  • limit
    integer
  • min_failed_prs
    integer
  • repo
    string
  • runner
    string
    One of: "jest""pytest"
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/flaky_tests
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/flaky_tests/

Example response

Status 200
RESPONSE
{
"items": [
{
"runner": "pytest",
"nodeid": "string",
"selector": "string",
"classification": "confirmed_flake",
"same_commit_recovery_run_count": 0,
"failed_run_count": 0,
"failed_pr_count": 0,
"master_failed_run_count": 0,
"quarantined_failed_run_count": 0,
"last_signal_at": "2019-08-24T14:15:22Z"
}
],
"truncated": true,
"limit": 0
}
Status 400 Invalid date, threshold, limit, runner, or source_id, or a window longer than 30 days.

Retrieve engineering analytics flaky

The active test-health queue: pytest and Jest tests worth acting on now, from the per-test CI spans, over a window (default -7d, maximum 30 days). Evidence is counted per CI run, never per span or run attempt. A test is a 'confirmed_flake' when one commit both failed and passed it (a 'Re-run failed jobs' attempt went green, or an in-job retry recovered it); 'quarantined' when a tolerated failure is recorded while it is masked; otherwise 'suspected_regression'. It qualifies on any same-commit recovery, any master/main failure, a quarantined failure, or failures on at least min_failed_prs distinct PRs. Counts are absolute, never rates: CI emits every failure but omits ordinary passing spans, so there is no execution denominator. 'suspected_regression' means no recovery was recorded in this data, not that the test never flakes.

Required API key scopes

engineering_analytics:read

Query parameters

  • date_from
    string
  • date_to
    string
  • limit
    integer
  • min_failed_prs
    integer
  • repo
    string
  • runner
    string
    One of: "jest""pytest"
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/flaky_tests
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/flaky_tests/

Example response

Status 200
RESPONSE
{
"items": [
{
"runner": "pytest",
"nodeid": "string",
"selector": "string",
"classification": "confirmed_flake",
"same_commit_recovery_run_count": 0,
"failed_run_count": 0,
"failed_pr_count": 0,
"master_failed_run_count": 0,
"quarantined_failed_run_count": 0,
"last_signal_at": "2019-08-24T14:15:22Z"
}
],
"truncated": true,
"limit": 0
}
Status 400 Invalid date, threshold, limit, runner, or source_id, or a window longer than 30 days.

Retrieve engineering analytics job

Per-job aggregates for one workflow over a window (default -30d), one row per de-sharded job name (matrix shards aggregate together), busiest first: queue p50, duration p50/p95, failure rate, retry pressure, run share (below 1.0 = conditional job), and billable cost. Optionally scope to a single git branch via branch or one run group via run_scope. Jobs always need their run as context: this is the aggregate view; use workflow_jobs for one run's jobs. Empty when the job-level source isn't synced.

Required API key scopes

engineering_analytics:read

Query parameters

  • branch
    string
  • date_from
    string
  • date_to
    string
  • repo
    string
  • run_scope
    string
    One of: "all""default_branch""merge_queue""pull_request"
  • source_id
    string
  • workflow_name
    string

Example request

GET /api/projects/:project_id/engineering_analytics/job_aggregates
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/job_aggregates/

Example response

Status 200
RESPONSE
{
"job_name": "string",
"job_count": 0,
"shard_count": 0,
"runs_in": 0,
"run_share": 0,
"queue_p50_seconds": 0,
"p50_seconds": 0,
"p95_seconds": 0,
"failure_rate": 0,
"retry_job_count": 0,
"billable_minutes": 0,
"estimated_cost_usd": 0
}
Status 400 Missing workflow_name, or invalid date, run_scope, or source_id.

Retrieve engineering analytics job

Per-job aggregates for one workflow over a window (default -30d), one row per de-sharded job name (matrix shards aggregate together), busiest first: queue p50, duration p50/p95, failure rate, retry pressure, run share (below 1.0 = conditional job), and billable cost. Optionally scope to a single git branch via branch or one run group via run_scope. Jobs always need their run as context: this is the aggregate view; use workflow_jobs for one run's jobs. Empty when the job-level source isn't synced.

Required API key scopes

engineering_analytics:read

Query parameters

  • branch
    string
  • date_from
    string
  • date_to
    string
  • repo
    string
  • run_scope
    string
    One of: "all""default_branch""merge_queue""pull_request"
  • source_id
    string
  • workflow_name
    string

Example request

GET /api/projects/:project_id/engineering_analytics/job_aggregates
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/job_aggregates/

Example response

Status 200
RESPONSE
{
"job_name": "string",
"job_count": 0,
"shard_count": 0,
"runs_in": 0,
"run_share": 0,
"queue_p50_seconds": 0,
"p50_seconds": 0,
"p95_seconds": 0,
"failure_rate": 0,
"retry_job_count": 0,
"billable_minutes": 0,
"estimated_cost_usd": 0
}
Status 400 Missing workflow_name, or invalid date, run_scope, or source_id.

Retrieve engineering analytics job log

What one GitHub Actions job's log says it did: cache restores (hit, older cache, miss, restore failed) and migrations applied, for the job and per step. Reads the log from GitHub on demand. Only a completed job's answer is cached. log_read is false, never an error, when there is no log to read: a Depot CI job, a job the source does not hold, an expired log, or a failed fetch.

Required API key scopes

engineering_analytics:read

Query parameters

  • ci_engine
    string
    One of: "github_actions""depot_ci"
  • job_id
    integer
  • repo
    string
  • run_id
    integer
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/job_log_insights
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/job_log_insights/

Example response

Status 200
RESPONSE
{
"job": [
{
"kind": "cache",
"state": "hit",
"count": 0,
"detail": [
"string"
]
}
],
"steps": [
{
"badges": [
{
"kind": "cache",
"state": "hit",
"count": 0,
"detail": [
"string"
]
}
],
"number": 0
}
],
"log_read": true,
"attributed_to_steps": true,
"log_truncated": true
}
Status 400 Missing or invalid repo, run_id, job_id, ci_engine or source_id, or an ambiguous job_id.

Retrieve engineering analytics job log

What one GitHub Actions job's log says it did: cache restores (hit, older cache, miss, restore failed) and migrations applied, for the job and per step. Reads the log from GitHub on demand. Only a completed job's answer is cached. log_read is false, never an error, when there is no log to read: a Depot CI job, a job the source does not hold, an expired log, or a failed fetch.

Required API key scopes

engineering_analytics:read

Query parameters

  • ci_engine
    string
    One of: "github_actions""depot_ci"
  • job_id
    integer
  • repo
    string
  • run_id
    integer
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/job_log_insights
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/job_log_insights/

Example response

Status 200
RESPONSE
{
"job": [
{
"kind": "cache",
"state": "hit",
"count": 0,
"detail": [
"string"
]
}
],
"steps": [
{
"badges": [
{
"kind": "cache",
"state": "hit",
"count": 0,
"detail": [
"string"
]
}
],
"number": 0
}
],
"log_read": true,
"attributed_to_steps": true,
"log_truncated": true
}
Status 400 Missing or invalid repo, run_id, job_id, ci_engine or source_id, or an ambiguous job_id.

Retrieve engineering analytics master

Default-branch failures over a window (default -24h), grouped error-tracking style by (workflow, de-sharded failing job) with a run count and first/last seen, newest group first. branch overrides the detected default branch. PR-branch failures are deliberately excluded: at monorepo volume a flat feed is a firehose; those surface per PR. Groups degrade to workflow level (failed_job '') when the job-level source isn't synced.

Required API key scopes

engineering_analytics:read

Query parameters

  • branch
    string
  • date_from
    string
  • date_to
    string
  • repo
    string
  • source_id
    string

Example request

GET /api/projects/:project_id/engineering_analytics/master_failures
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/master_failures/

Example response

Status 200
RESPONSE
{
"repo": {
"provider": "string",
"owner": "string",
"name": "string"
},
"workflow_name": "string",
"failed_job": "string",
"run_count": 0,
"first_seen": "2019-08-24T14:15:22Z",
"last_seen": "2019-08-24T14:15:22Z",
"latest_run_id": 0,
"latest_ci_engine": "github_actions"
}
Status 400 Invalid date_from, date_to, or source_id, or a window over 366 days.

Retrieve engineering analytics master

Default-branch failures over a window (default -24h), grouped error-tracking style by (workflow, de-sharded failing job) with a run count and first/last seen, newest group first. branch overrides the detected default branch. PR-branch failures are deliberately excluded: at monorepo volume a flat feed is a firehose; those surface per PR. Groups degrade to workflow level (failed_job '') when the job-level source isn't synced.

Required API key scopes

engineering_analytics:read

Query parameters

  • branch
    string
  • date_from
    string
  • date_to
    string
  • repo
    string
  • source_id
    string

Example request

GET /api/projects/:project_id/engineering_analytics/master_failures
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/master_failures/

Example response

Status 200
RESPONSE
{
"repo": {
"provider": "string",
"owner": "string",
"name": "string"
},
"workflow_name": "string",
"failed_job": "string",
"run_count": 0,
"first_seen": "2019-08-24T14:15:22Z",
"last_seen": "2019-08-24T14:15:22Z",
"latest_run_id": 0,
"latest_ci_engine": "github_actions"
}
Status 400 Invalid date_from, date_to, or source_id, or a window over 366 days.

Retrieve engineering analytics pr

Estimated CI cost for a pull request, summed over the jobs of all its workflow runs. Billable self-hosted Linux runners only: provider-hosted (free GitHub-hosted) and non-Linux jobs are excluded. Every figure is zero/null with jobs_available false when the job-level source isn't synced yet. llm_spend carries the agent LLM token spend attributed to the PR by git branch, or null when no $ai_generation event matched.

Required API key scopes

engineering_analytics:read

Query parameters

  • pr_number
    integer
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/pr_cost
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/pr_cost/

Example response

Status 200
RESPONSE
{
"by_workflow": [
{
"workflow_name": "string",
"billable_minutes": 0.1,
"estimated_cost_usd": 0,
"costed_jobs": 0,
"unsettled_jobs": 0,
"excluded_jobs": 0
}
],
"by_run": [
{
"run_id": 0,
"run_attempt": 0,
"billable_minutes": 0.1,
"estimated_cost_usd": 0,
"ci_engine": "github_actions"
}
],
"llm_spend": {
"cost_usd": 0.1,
"input_tokens": 0,
"output_tokens": 0,
"generations": 0
},
"jobs_available": true,
"billable_minutes": 0.1,
"estimated_cost_usd": 0,
"costed_jobs": 0,
"unsettled_jobs": 0,
"excluded_jobs": 0
}
Status 400 Missing pr_number/repo, or invalid repo or source_id.

Retrieve engineering analytics pr

Estimated CI cost for a pull request, summed over the jobs of all its workflow runs. Billable self-hosted Linux runners only: provider-hosted (free GitHub-hosted) and non-Linux jobs are excluded. Every figure is zero/null with jobs_available false when the job-level source isn't synced yet. llm_spend carries the agent LLM token spend attributed to the PR by git branch, or null when no $ai_generation event matched.

Required API key scopes

engineering_analytics:read

Query parameters

  • pr_number
    integer
  • repo
    string
  • source_id
    string

Response


Example request

GET /api/projects/:project_id/engineering_analytics/pr_cost
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/engineering_analytics/pr_cost/

Example response

Status 200
RESPONSE
{
"by_workflow": [
{
"workflow_name": "string",
"billable_minutes": 0.1,
"estimated_cost_usd": 0,
"costed_jobs": 0,
"unsettled_jobs": 0,
"excluded_jobs": 0
}
],
"by_run": [
{
"run_id": 0,
"run_attempt": 0,
"billable_minutes": 0.1,
"estimated_cost_usd": 0,
"ci_engine": "github_actions"
}
],
"llm_spend": {
"cost_usd": 0.1,
"input_tokens": 0,
"output_tokens": 0,
"generations": 0
},
"jobs_available": true,
"billable_minutes": 0.1,
"estimated_cost_usd": 0,
"costed_jobs": 0,
"unsettled_jobs": 0,
"excluded_jobs": 0
}
Status 400 Missing pr_number/repo, or invalid repo or source_id.