neosourceDocs
Search docs

Get the stack containing this PR

GET/api/repos/{owner}/{repo}/pulls/{number}/stack

getPullRequestStack

Returns the linear stack of PRs this PR participates in, ordered bottom-first. For a non-stacked PR the result is `[pr]`.

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/stack'

fetch

fetch("https://neosource.dev/api/repos/OWNER/REPO/pulls/NUMBER/stack", {
  method: "GET",
});

Path parameters

ownerrequired

Repository owner or organization slug.

string

reporequired

Repository name.

string

numberrequired

Change request number.

integerint32

Responses

200Stack

application/json

PullRequestStackResponse

object

stackrequired

array

Stack ordered bottom-first: the PR closest to the default branch is index 0, then its child, then grandchild, etc. Includes the queried PR. For a non-stacked PR, the list is just `[pr]`.

items

PullRequestResponse

object

author_display_name

string | null

author_github_login

string | null

Last-seen GitHub login for authors with a linked GitHub identity (always set for ghosts).

author_handle

string | null

Author 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_idrequired

string

author_kind
one of
auto_merge_enabled_at

integer | nullint64

When auto-merge was armed (ms since epoch); set together with `auto_merge_enabled_by`.

auto_merge_enabled_by

string | null

Account 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_idrequired

string

32-byte durable change identity (hex). Survives force-push / rebase.

created_atrequired

integerint64

descriptionrequired

string

draftrequired

boolean

head_commit

string | null

40-char Git OID hex of the source branch's current tip, or `null` before the first push resolves one.

merge_commit

string | null

40-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
merged_at

integer | nullint64

When the merge landed (ms since epoch). Unlike `updated_at` this never moves again, so it is the field to render as "merged <when>".

merged_by

string | null

Account 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_name

string | null

merged_by_github_login

string | null

merged_by_handle

string | null

Merger 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_repo

string | null

For 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.

numberrequired

integerint32

originrequired
PrOrigin
parent_pr_id

string | null

Parent 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_idrequired

string

repo_idrequired

string

source_branchrequired

string

source_repo_idrequired

string

Repo the source branch lives in. Equals `repo_id` for a same-repo PR; the contributor's fork for a fork PR.

statusrequired
PullRequestStatus
target_branchrequired

string

titlerequired

string

updated_atrequired

integerint64

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.

AccountKind

string

Rust mirror of the Pg `account_kind` enum (`accounts.kind`). `Ghost` rows are imported-author placeholders (GitHub metadata import, plans/github-metadata-import.md §6): `handle = gh-<github-id>`, `personal_workspace_id` NULL, no password, no sessions. They must never flow through `get_account*` (`AccountRow::into_record` CorruptData-errors on the NULL workspace) — author rendering goes through `PgGithubImportStore::authors_projection`, and claim-by-proof later promotes or merges them.

"human""bot""service""runner""ghost"

MergeMethod

string

How a pull request's commits land on its target branch. A repo carries two settings over this enum (`migrations/20260820120000_repo_merge_methods.sql`): the set it *permits* (`RepoRecord::allowed_merge_methods`, never empty) and the one the merge path reaches for when the request names none (`RepoRecord::default_merge_method`, always a member of that set — enforced by the settings route, which is the only place both columns are visible at once). `Default` is [`MergeMethod::Merge`] to match the column default, which is itself the pre-existing behaviour of every repo: before this setting existed, a merge always minted a two-parent commit. `Rebase` is deliberately absent rather than merely unimplemented — it replays N commits, can conflict per commit, and rewrites the SHAs the stacked-PR re-parent invariant leans on (`plans/archive/pr-merge-methods-2026-08.md` §"Not doing"). Adding it later is one `ALTER TYPE merge_method ADD VALUE` plus an arm here, which is why the stored shape is an enum array and not a pair of booleans.

"merge""squash"

MergedVia

string

How a pull request's merge was triggered — the companion to [`MergeMethod`], which says what the merge *minted*. The two are independent: a squash can land either by hand or by an armed auto-merge, and an imported mirror carries a trigger with no method at all.

"manual""auto""import"

PrOrigin

string

Provenance of a pull request. `Native` PRs are created in neosource and are fully mutable; `GithubMirror` PRs are read-only imports of GitHub pull requests (one-directional metadata sync). Store-level single-row lookups filter to `Native` so a fork mirror — which stores GitHub head-ref names like `main`/`patch-1` — can never mask a native PR nor be advanced by a native push.

"native""github_mirror"

PullRequestStatus

string

Lifecycle status of a pull request.

"open""merged""closed"