List CI checks for a PR's head commit
GET/api/repos/{owner}/{repo}/pulls/{number}/checks
listPullRequestChecks
Derives one check per job of the workflow runs whose trigger commit equals the PR's current head — runs for a previous (stale) head are never counted. One check per context: where several runs report the same context (a re-run attempt, a dispatch on top of a `pull_request` run) the NEWEST run's verdict wins, matching the merge gate. There is no stored checks state; this is a pure projection of the CI runs.
Authentication is not described for this operation in the spec — that does not mean it is public. Check tokens and scopes.
curl
curl -X GET 'https://neosource.dev/api/repos/OWNER/REPO/pulls/NUMBER/checks'fetch
fetch("https://neosource.dev/api/repos/OWNER/REPO/pulls/NUMBER/checks", {
method: "GET",
});Path parameters
ownerrequiredRepository owner or organization slug.
reporequiredRepository name.
numberrequiredChange request number.
Responses
200Derived checks + summary
application/json
Standard errors
Bodies documented once for the whole API — see standard errors.
- 400Bad Request — one of: invalid_input
- 403Forbidden — one of: forbidden
- 404Not Found — one of: not_found
- 423Locked — one of: busy
- 429Rate limited — retry after the `Retry-After` header
- 500Internal server error
- 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
- 504Gateway timeout — the request exceeded the server's handling budget
Schemas
Referenced above. Listed here rather than expanded inline, so the same definition is not repeated at every level.
CheckState
Wire-level state of one check. Deliberately the four-value GitHub commit-status vocabulary (`pending`/`success`/`failure`/`error`) so run-derived checks and externally-posted statuses (P2.2) aggregate in one space.
"pending""success""failure""error"
CheckRun
One CI check on a PR's head commit: the projection of one job of one workflow run (later also one external commit status).
contextrequiredStable identity of the check: `"<workflow name> / <job key>"`, matrix legs append their values. Branch protection (P2.3) matches required checks against this string.
descriptionHuman-readable detail (held-for-approval, skipped, …); P2.5 fills per-run test summaries in here.
job_idThe job row this check projects from (UUID). Absent only on the aggregate check of a job split into matrix legs, which is the whole job rather than one row; every leg's own check carries its row, since the legs share `job_key`.
job_keyrequiredquarantined`true` when this check is red (`failure`/`error`) but was soft-failed out of the merge gate's `blocked_by` because every one of its failing tests is quarantined (P3.3 of `plans/ci-merge-gating-polish-2026-07.md`). The check still reports its real (red) `state` — this only badges it "quarantined (non-blocking)". Always `false` when merge gating isn't wired, the check is green/pending, or the red isn't quarantine-eligible.
run_idrequiredWorkflow run the check derives from (UUID).
skipped`true` when the job never ran — gated off by its job-level `if:`, or skipped because a `needs:` predecessor did not succeed. The `state` stays `success` (GitHub scores a skipped check as passing, so it must not block a merge on a required check that was never meant to run on this ref); this flag is what lets the UI render "Skipped" rather than a green tick implying work happened.
staterequiredsuperseded`true` when the job never finished because the merge queue SUPERSEDED its run: the PR head's run, cancelled once the queue's candidate had `merge_group` runs of the same workflow (ADR 0160). The `state` is `pending`, not `error`: nothing failed, so it must not render red, and the head was not verified, so it is never green — a PR that leaves the queue needs a re-run before it merges directly. Render it as "superseded by the merge queue", not as in flight: it will not resolve on its own.
target_urlrequiredApp path of the run page (`/{owner}/{repo}/actions/runs/{run_id}`).
ChecksSummary
Roll-up of the check states for the merge box. Counted over the newest-run-per-context set (`neosource_forge::head_checks`), so a run that a re-run superseded is not a second check.
failedrequired`failure` + `error` states — both render red and both block.
pendingrequiredskippedChecks whose job never ran (gated off by a job-level `if:`, or a `needs:` predecessor did not succeed). Counted separately from `success`; `success + failed + pending + skipped == total`.
successrequiredChecks that ran and passed. Deliberately EXCLUDES skipped ones: a skipped check carries `state: success` so it cannot block a merge, but counting it as "passed" would tell the reader that work happened when it did not — the same claim the per-check `skipped` flag exists to stop the UI making.
supersededChecks the merge queue superseded (`CheckRun::superseded`, ADR 0160): a SUBSET of `pending` (`superseded <= pending`) — they are counted in `pending` too, so a reader that ignores this field still sees the head as not green — never in `failed` (nothing failed). Render `pending - superseded` as in flight and these as superseded.
totalrequired
MergeQueueGate
Which commit's checks an entry's gate reads — derived from the private preparation, so a list row can show the CI that actually decides it instead of inferring that from which commit hexes are present.
"speculative""pr_head""unprepared"