List pull requests
GET/api/repos/{owner}/{repo}/pulls
listPullRequests
Lists pull requests for a repository, newest number first, with an optional status filter. Keyset-paginated: pass a previous response's `next_cursor` back as `cursor` for the next (older) page. `counts` (the whole-repo tab badges) is present only on a request with no `cursor`. `offset` is deprecated but still honoured; `cursor` together with a positive `offset` is a 400.
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'fetch
fetch("https://neosource.dev/api/repos/OWNER/REPO/pulls", {
method: "GET",
});neo
neo pr list OWNER/REPOPath parameters
ownerrequiredRepository owner or organization slug.
reporequiredRepository name.
Query parameters
statusFilter by status.
limitMaximum number of results.
default
30offsetDeprecated: pass `cursor` instead. Rows to skip before the page; still honoured, and a request carrying it still gets `counts`. Sending a positive `offset` together with `cursor` is a 400.
default
0cursorOpaque pagination cursor from a previous response's `next_cursor`: the next (older) page. A request with a cursor gets `counts: null`.
viewRow shape: `full` (default) or `summary`. Any other value is a 400.
Which row shape `GET …/pulls` answers with. `full` (the default) is every field of [`PullRequestResponse`], byte for byte what the route has always sent — the shape every `neo` build decodes, and prints through `neo pr list --json`. `summary` is [`PullRequestListItem`]: what a list renders, without the Markdown body or the detail-only fields. Only a caller that asks gets it.
"full""summary"
Responses
200Change request list
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.
PullRequestResponse
author_display_nameauthor_github_loginLast-seen GitHub login for authors with a linked GitHub identity (always set for ghosts).
author_handleAuthor fields resolved at read time (route-layer enrichment via the ghost-safe authors projection — plans/github-metadata-import.md §7), exactly as on [`crate::IssueResponse`]. Filled on every READ — list, detail, and both context packs. `None` on a mutation receipt (the caller already has the row it just wrote) or when the account row is gone.
author_idrequiredauthor_kind- one of
auto_merge_enabled_atWhen auto-merge was armed (ms since epoch); set together with `auto_merge_enabled_by`.
auto_merge_enabled_byAccount id that armed auto-merge (merge-when-green); `null` = off. On an OPEN PR this means "will merge, as this account, the moment the merge gate reports mergeable". Cleared automatically when the head advances (new commits disarm).
change_idrequired32-byte durable change identity (hex). Survives force-push / rebase.
created_atrequireddescriptionrequireddraftrequiredhead_commit40-char Git OID hex of the source branch's current tip, or `null` before the first push resolves one.
merge_commit40-char Git OID hex of the commit the merge minted, or `null` when it minted none: an import, or a merge whose source was already reachable from the target.
merge_method- one of
merge_queue- one of
merged_atWhen the merge landed (ms since epoch). Unlike `updated_at` this never moves again, so it is the field to render as "merged <when>".
merged_byAccount credited with the merge, `null` until the PR merges — and also on a merged GitHub mirror, whose upstream merger the import payload does not carry. For a merge made with a service token this is the token's OWNER; the token itself is recorded in the operation log, not here.
merged_by_display_namemerged_by_github_loginmerged_by_handleMerger fields resolved at read time, exactly as the `author_*` group above and through the same batched projection call. `None` on a mutation receipt, on an unmerged PR, and when the account row is gone.
merged_by_kind- one of
merged_via- one of
mirror_head_repoFor a fork mirror, the GitHub `owner/name` of the fork the head lives in — a non-null value means "no local branch" (fork diff renders off the pinned OID). `null` for native PRs and same-repo mirrors.
numberrequiredoriginrequiredparent_pr_idParent PR id when this PR is part of a stack (its `target_branch` matches another open PR's `source_branch`). `None` for a non-stacked PR or for the bottom of a stack.
pr_idrequiredrepo_idrequiredsource_branchrequiredsource_repo_idRepo the source branch lives in. Equals `repo_id` for a same-repo PR; the contributor's fork for a fork PR. `null` once the source repository was deleted — such a pull request is kept as history but can never merge.
statusrequiredtarget_branchrequiredtitlerequiredupdated_atrequired
PullRequestListItem
One row of `GET …/pulls?view=summary`: what a list renders, not the whole PR. The fields a list surface reads: - the row itself (`PrListRow.svelte`, `neo pr list`'s table): title, number, branches, author, state badge, queue badge, mirror marker, and `head_commit` — the join key the `pulls/checks` roll-up is gated on; - the PR page's header, which paints from the clicked row before the detail lands (`pullDetailPlaceholder` in `neosource-app/src/lib/queries/pulls.ts`): the `merged_*` group feeds its "merged by X" line, and `pr_id` + `auto_merge_enabled_by` decide whether the row may seed it at all; - `author_id`: the author label's fallback when no handle resolved (`authorLabel` in `neosource-app/src/lib/utils/authors.ts`). Not carried, because no list reads them: the Markdown `description` (unbounded), `repo_id` (the request's own repo), `change_id`, `updated_at`, and the detail-only `source_repo_id`, `parent_pr_id`, `auto_merge_enabled_at`, `merge_commit`. The default `full` view and the detail endpoint carry them.
author_display_nameauthor_github_loginauthor_handleAs on [`PullRequestResponse`]: resolved at read time, `None` when the account row is gone.
author_idrequiredauthor_kind- one of
auto_merge_enabled_byAccount id that armed auto-merge; `null` = off.
created_atrequireddraftrequiredhead_commit40-char Git OID hex of the source branch's current tip.
merge_method- one of
merge_queue- one of
merged_atmerged_bymerged_by_display_namemerged_by_github_loginmerged_by_handlemerged_by_kind- one of
merged_via- one of
mirror_head_repoFork mirror's GitHub `owner/name`; see [`PullRequestResponse`].
numberrequiredoriginrequiredpr_idrequiredsource_branchrequiredstatusrequiredtarget_branchrequiredtitlerequired