Docs
Search docs

List the merge queue

GET/api/repos/{owner}/{repo}/merge-queue

listMergeQueue

Requires authentication using a bearer token or a session cookie — see tokens and scopes.

curl

curl -X GET 'https://neosource.dev/api/repos/OWNER/REPO/merge-queue' \
  -H 'Authorization: Bearer $NEOSOURCE_TOKEN'

fetch

fetch("https://neosource.dev/api/repos/OWNER/REPO/merge-queue", {
  method: "GET",
  headers: {
    Authorization: "Bearer $NEOSOURCE_TOKEN",
  },
});

Path parameters

ownerrequired

Repository owner or organization slug.

string

reporequired

Repository name.

string

Query parameters

target_branch

string | null

Responses

200Ordered merge queue

application/json

MergeQueueListResponse

object

entriesrequired

array

items

MergeQueueEntryResponse

all of

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.

PrMergeQueueSummary

object

`PartialEq` because the drive publishes an entry exactly when this — the face the API shows — differs from what the entry showed before the step (`merge_queue.rs`, `QueueFrames`): a record rewrite that changes nothing visible (a `blocked_by` refresh every tick, a `waits` verdict) must not nudge every viewer's queue.

blocked_byrequired

array

items

string

enqueued_atrequired

integerint64

entry_idrequired

string

head_commitrequired

string

methodrequired

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"

position

integer | nullint64

speculative_head

string | null

staterequired

MergeQueueState

string

"queued""testing""merging""ejected"

target_branchrequired

string

MergeQueueCandidateChecks

object

What is running against a queue entry's candidate, joined SERVER-SIDE. The queue page used to fetch `/commits/{sha}/runs` once per entry on every poll — three entries were four requests every five seconds. The join lives here so the page is one request, and, more to the point, so the row shows the SAME set the merge gate judges: `neosource_forge::head_checks` collapses the candidate's runs to the newest per context (a re-run supersedes the attempt before it), and a client that rolled up the raw run list would paint a red row beside an entry the gate is about to publish. One collapse, stated once, read by both.

checks_summaryrequired

ChecksSummary

object

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

integerint32

`failure` + `error` states — both render red and both block.

pendingrequired

integerint32

skipped

integerint32

Checks 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`.

successrequired

integerint32

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

superseded

integerint32

Checks 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

integerint32

headrequired

string

The candidate commit judged (40-char Git OID hex) — equal to the entry's `speculative_head`, repeated so the block is self-describing.

runsrequired

array

The runs that contributed a surviving check, newest first and distinct — what the row links to. Empty exactly when `checks_summary.total` is zero.

items

MergeQueueCandidateRun

object

One surviving run on a queue candidate, as much as a queue row links to. Not the full `WorkflowRunResponse`: that carries a cause payload, a toolchain manifest and a test summary, none of which a list row prints, and the queue is polled. `status` is the run's whole lifecycle — a terminal `succeeded` / `failed` / `cancelled` IS the conclusion, there is no separate conclusion enum on this platform.

finished_at

integer | nullint64

Terminal time, epoch milliseconds; `null` while the run is in flight.

idrequired

string

Run id (UUID hex) — `/{owner}/{repo}/actions/runs/{id}`.

run_numberrequired

integerint64

Per-workflow ordinal (`github.run_number`).

started_at

integer | nullint64

First job start, epoch milliseconds; `null` while the run is queued. With `finished_at`, what the row's elapsed/duration is measured from.

statusrequired

WorkflowRunStatus

string

Lifecycle of a workflow run. Mirrors the GHA-shaped surface that the SPA renders. The serde `snake_case` strings are the wire vocabulary the API emits (pinned by the `enum_wire_consistency` tests).

"pending_approval""queued""quota_blocked""concurrency_blocked""running""cancelling""succeeded""failed""cancelled"

workflow_namerequired

string

The workflow's declared `name:`, the check context's prefix.

workflows

array

The same set split by workflow, in row order (by path, then id) — what a queue row paints one icon per, as the PR list does.

items

WorkflowCheck

object

One workflow's newest run on a commit — one icon of a commit or PR row, beside the workflow's siblings, where a single roll-up would hide which workflow was red (`WorkflowVerdict` in neosource-core). Rows receive these already ordered: by `workflow_path`, then `workflow_id`, an unregistered workflow last — never by state.

run_idrequired

string

The newest run (latest attempt) of this workflow on the commit (UUID).

run_numberrequired

integerint64

skippedrequired

boolean

Every job of the run was skipped: `status` is `succeeded`, but no work ran.

statusrequired

WorkflowRunStatus

string

Lifecycle of a workflow run. Mirrors the GHA-shaped surface that the SPA renders. The serde `snake_case` strings are the wire vocabulary the API emits (pinned by the `enum_wire_consistency` tests).

"pending_approval""queued""quota_blocked""concurrency_blocked""running""cancelling""succeeded""failed""cancelled"

supersededrequired

boolean

The merge queue superseded and cancelled this run (ADR 0160): render neutral, neither red nor in flight.

workflow_idrequired

string

Workflow id (UUID).

workflow_namerequired

string

The workflow's declared `name:` as the run pinned it.

workflow_path

string | null

The workflow file's repo path; `null` when the workflow is no longer registered.

MergeQueueGate

string

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"