> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trunk.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Merge Queue API (v2)

> REST API for merge queues, the pull requests in them, and the testing they run.

The v2 Merge Queue API lets you manage merge queues and the pull requests in them, read the order the queue will test them in, and inspect the CI runs it starts. It is an HTTP REST API that returns JSON and uses standard HTTP status codes.

The base URL is `https://api.trunk.io`. Endpoint paths already include `/v2` (for example, `/v2/merge-queues`), so don't add it to the host.

Use v2 for new integrations. The [v1 API](https://docs.trunk.io/merge-queue/reference/merge) keeps working unchanged. To move existing code to v2, see [Migrate from the v1 API](https://docs.trunk.io/merge-queue/reference/api-v2/migrate-from-v1.md).

## Before you start

Merge queues are GitHub-only. Install the Trunk GitHub App on the repository, and create a merge queue for the branch you merge into. See [Install and create your queue](https://docs.trunk.io/merge-queue/getting-started/install-and-create-your-queue.md), or [create the queue with the API](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/create-a-merge-queue.md).

## Concepts

* **Queue entry**: a pull request's place in a merge queue, under `queueEntry` on a pull request. Its `id` differs from the pull request's `id`. Endpoints under `/v2/pull-requests/{id}` take the pull request's `id`.
* **Queue entry state**: `notReady` (submitted, but waiting on a requirement such as passing checks or impacted targets), `pending` (ready, waiting to test), `testing`, `testsPassed`, and `pendingFailure`. The final states are `merged`, `failed`, and `cancelled`. `queueEntry.readiness` explains a `notReady` entry. A `pendingFailure` entry's tests failed, and the queue holds it to learn whether the failure is its own, for example while the pull requests ahead of it finish. See [Pending failure depth](https://docs.trunk.io/merge-queue/optimizations/pending-failure-depth.md).
* **Verification run**: one CI run the queue started to test a pull request, or a [batch](https://docs.trunk.io/merge-queue/optimizations/batching.md) of them. When a batch fails, the queue splits it to find the culprit (**bisection**). Each split is its own verification run.
* **Mode**: `queue` mode (**Single** in the app) puts pull requests in one line, each tested on top of the ones ahead of it, several at a time. `graph` mode (**Parallel** in the app) gives unrelated pull requests separate lines, based on the [impacted targets](https://docs.trunk.io/merge-queue/optimizations/parallel-queues) CI uploads for each.
* **Priority**: lower `priorityValue` numbers test first. The names are `urgent` (0), `high` (10), `medium` (100), and `low` (200). Send a number as `priorityValue` or a name as `priorityName`. Without either, a pull request gets `medium` (100). **`urgent` (or `priorityValue: 0`) restarts lower-priority pull requests that are already testing**, so reserve it for emergencies. See [Priority merging](https://docs.trunk.io/merge-queue/optimizations/priority-merging.md).
* **Direct to queue**: `direct: true` sends a pull request to the queue before its branch protection is satisfied. See [Direct-to-Queue](https://docs.trunk.io/merge-queue/using-the-queue/direct-to-queue).

## Authentication

Authenticate automation with an API key, sent as `Authorization: Bearer <key>`:

```bash theme={"system"}
curl https://api.trunk.io/v2/merge-queues \
  -H "Authorization: Bearer $TRUNK_API_KEY"
```

An organization admin creates keys under **Settings** → **Developer** → **API Keys**. A key with no permissions can read merge queues but can't change them. The organization API token works only with the v1 API.

A GitHub Actions job that uploads impacted targets can [authenticate without a key](https://docs.trunk.io/merge-queue/reference/api-v2/github-actions.md). See [Authentication](https://docs.trunk.io/merge-queue/reference/api-v2/authentication.md) for permissions, rotation, and errors.

## Finding IDs

Endpoints address resources by `id`. Look IDs up once and store them:

1. **Queue:** [`GET /v2/merge-queues`](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/list-merge-queues) lists your organization's queues, each with its `id`, `repositoryId`, `repositoryUrl`, and `targetBranch`. To list one repository's queues, get its ID from [`GET /v2/repositories?providerUrl=https://github.com/<owner>/<repo>`](https://docs.trunk.io/merge-queue/reference/api-v2/repositories/resolve-a-repository-by-its-provider-url) (`.data[0].id`), then call `GET /v2/merge-queues?repositoryId=<id>&targetBranch=<branch>`.
2. **Pull request:** [`GET /v2/pull-requests?repositoryId=…&number=…`](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/resolve-pull-requests-by-repository-coordinates) resolves up to 50 comma-separated pull request numbers at once (set `limit=50`, since the default page is 25), or one head `branch`. It finds only pull requests Trunk's GitHub App has already seen. If you just opened one, retry shortly.

```bash theme={"system"}
curl "https://api.trunk.io/v2/pull-requests?repositoryId=7c9e6679-7425-40de-944b-e07fc1f90ae7&number=4901" \
  -H "Authorization: Bearer $TRUNK_API_KEY"
```

## Submit and wait for a merge

Submitting needs a key with the **Merge and cancel PRs** [permission](https://docs.trunk.io/merge-queue/reference/api-v2/authentication.md#permissions). Submit takes the pull request's `number` in the body, so it needs only the queue's ID and has no lookup delay:

```bash theme={"system"}
curl -X POST https://api.trunk.io/v2/merge-queues/xK9mP2nQ/pull-requests \
  -H "Authorization: Bearer $TRUNK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "number": 4901 }'
```

Its `201` response is the pull request; keep its `id` for polling.

* If the pull request is already queued here (not yet merged, failed, or cancelled), submit returns `409 PR_ALREADY_ENQUEUED` and changes nothing. [Look up its `id`](#finding-ids) instead, using the queue's `repositoryId` from [`GET /v2/merge-queues/{id}`](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-a-merge-queue).
* If Trunk can't enqueue it, submit returns `422 PR_NOT_ENQUEUEABLE` with the reason in `message`. For example:
  * The pull request doesn't exist.
  * It targets a different branch from the queue's. A stacked pull request may target another pull request's branch, as long as the stack ends at the queue's branch.
  * A repository ruleset can block it.
  * It's still in another of the repository's queues. Look up the pull request, read `queueEntry.mergeQueueId`, and dequeue it there first.
* A closed pull request is accepted but stays `notReady`.

To wait for a pull request to merge, poll [`GET /v2/pull-requests/{id}`](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/get-a-pull-request) every 30 to 60 seconds until `queueEntry.state` is `merged`, `failed`, or `cancelled`, or subscribe to [Merge Queue webhooks](https://docs.trunk.io/merge-queue/webhooks.md). The API itself has no webhooks.

* Read `queueEntry.state`, not the top-level `state`, which is the pull request's state on GitHub.
* `queueEntry.state` can go back to `notReady` before the entry ends. A push to the pull request sends a queued entry back to `notReady` to wait on the new commit, and a resubmitted pull request reuses its entry and starts again at `notReady`. Keep polling.
* Stop if `queueEntry` disappears or its `mergeQueueId` changes, and report the outcome as unknown. This happens when a failed or cancelled pull request is submitted to another queue, or its queue is deleted.
* Send the last response's `ETag` in `If-None-Match`. If nothing changed, you get `304` with no body.
* Set a deadline of your own. A pull request can stay `notReady` for a long time; the queue cancels it only if its `notReadyTimeoutMinutes` [setting](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/update-a-merge-queues-configuration.md) is set.
* Don't stop when `ci.pollAfterSeconds` is `null`. It describes CI on the pull request's own head commit, not its place in the queue.

To find out why a pull request failed, read the latest transition in its [queue-entry history](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/list-a-pull-requests-queue-entry-state-history.md) (`direction=newest`). The [failure reason reference](https://docs.trunk.io/merge-queue/using-the-queue/handle-failed-pull-requests.md#failure-reason-reference) explains each `reason`. When a required check failed, `failed.failureCausingChecks` names the checks, and `verificationRunId` leads to the [verification run](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeueverificationruns/get-a-verification-run.md) and its `checks`.

## Pagination

Every list endpoint returns the same envelope:

```json theme={"system"}
{
  "data": [],
  "nextCursor": "AQEKZm9vYmFy",
  "hasMore": true
}
```

Pass `nextCursor` back verbatim as `cursor` to get the next page, until `hasMore` is `false`. Cursors are opaque, forward-only, and bound to the endpoint and filters they came from. `limit` sets the page size, from 1 to 100; the default is 25. `includeTotal=true` adds a `total` count at the cost of an extra query.

List order is not queue order. A queue's pull request list is ordered by when each pull request was first submitted to the queue, newest first, and a resubmission doesn't move it. For the order the queue will test pull requests in, use [`GET /v2/merge-queues/{id}/order`](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-a-merge-queues-dispatch-order). Its lists carry only each pull request's `id`, `number`, `title`, `sha`, and `url`. For state or priority, match by `id` against `GET /v2/merge-queues/{id}/pull-requests?state=pending,testing,testsPassed,pendingFailure`.

## Errors

Every error the API itself returns has this shape:

```json theme={"system"}
{
  "error": {
    "code": "MERGE_QUEUE_NOT_FOUND",
    "message": "No merge queue found with ID xK9mP2nQ"
  }
}
```

Switch on `code`, which is stable. `message` is for people and may change at any time.

Some responses don't have this shape. Trunk's edge answers `401`, `403` for some credential problems, `429`, and gateway errors such as `503` before the request reaches the API. The API itself answers `413` for a body over 512 KB and `504` for a request that runs past its time limit (usually 5 seconds), both as plain text. Read `error.code` only when the body is JSON with an `error` object, and otherwise branch on the status code. See [Authentication errors](https://docs.trunk.io/merge-queue/reference/api-v2/authentication.md#authentication-errors).

* **`404` also means "not yours".** A read of a resource in another organization returns `404`, not `403`, so the API never reveals whether it exists.
* **`403 INSUFFICIENT_PERMISSIONS`** means your credential is valid but not permitted to take that action.
* **`422`** means the request can't succeed as sent. Retrying it unchanged gets the same answer until something about the pull request or repository changes.

Every response from the API carries an `X-Request-Id` header; edge responses may not. Include it when you contact support.

## Rate limits

Most requests share one limit of 100 per second per organization, across every API key, user, and CLI session in it. Some requests have limits of their own and don't count toward it, including:

* **`GET` requests on paths that start with `/v2/pull-requests`**, such as `GET /v2/pull-requests/{id}` and its history: 5 per second per API key or user. `GET /v2/merge-queues/{id}/pull-requests` uses the organization's limit.
* **Metrics** (`GET /v2/merge-queues/metrics` and `GET /v2/merge-queues/{id}/metrics`): 5 per second per organization.
* **Impacted-target uploads from a [GitHub Actions login](https://docs.trunk.io/merge-queue/reference/api-v2/github-actions.md)**: 10 per second per repository, with a separate allowance for fork pull requests.

A request over a limit gets `429`.

## Retrying

* **Reads** are safe to retry on `429`, `500`, `502`, `503`, `504`, and network errors. Back off exponentially between attempts.
* **Writes** don't honor `Idempotency-Key` yet. A write that times out or returns `500`, `502`, `503`, or `504` has an unknown outcome, so read the resource back before retrying. A blind retry can, for example, restart a pull request's tests twice. Some writes, such as `PATCH …/config` and `PUT /v2/impacted-targets`, set a value and are safe to repeat.

## Compatibility

Within v2, Trunk may add endpoints, optional request parameters, optional response fields, and new enum values, including error codes and queue-entry states. Removals and changes in meaning require a new major version. **Tolerate values and fields you don't recognize.**

Most enum values are camelCase. These are uppercase: error `code`s, a transition's `reason` and `pendingFailure.eventualFailureReason`, a check's `providerStatus` and `providerConclusion`, and `failureCausingChecks[].conclusion`.

## Endpoints

Each endpoint page is also available as Markdown, including its OpenAPI definition, by adding `.md` to its URL.

### Merge queues

> **[List merge queues](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/list-merge-queues.md)**

> **[Create a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/create-a-merge-queue.md)**

> **[Get a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-a-merge-queue.md)**

> **[Update a merge queue's configuration](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/update-a-merge-queues-configuration.md)**

> **[Switch a merge queue's mode](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/switch-a-merge-queues-mode.md)**

> **[Pause a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/pause-a-merge-queue.md)**

> **[Resume a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/resume-a-merge-queue.md)**

> **[Drain a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/drain-a-merge-queue.md)**

> **[Delete a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/delete-a-merge-queue.md)**

### Queue order

The order shows what the queue tests next. The graph shows why pull requests depend on each other, not when they run.

> **[Get a merge queue's dispatch order](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-a-merge-queues-dispatch-order.md)**

> **[Get a merge queue's dependency graph](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-a-merge-queues-dependency-graph.md)**

### Pull requests

> **[Submit a pull request to a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/submit-a-pull-request-to-a-merge-queue.md)**

> **[List a merge queue's pull requests](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/list-a-merge-queues-pull-requests.md)**

> **[Resolve pull requests by repository coordinates](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/resolve-pull-requests-by-repository-coordinates.md)**

> **[Get a pull request](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/get-a-pull-request.md)**

> **[Reprioritize a queued pull request](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/reprioritize-a-queued-pull-request.md)**

> **[Update a queued pull request's entry](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/update-a-queued-pull-requests-entry.md)**

> **[Restart a queued pull request's tests](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/restart-a-queued-pull-requests-tests.md)**

> **[Dequeue a pull request](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/dequeue-a-pull-request.md)**

> **[List a pull request's queue-entry state history](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/list-a-pull-requests-queue-entry-state-history.md)**

> **[List queue-entry state history for several pull requests](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/list-queue-entry-state-history-for-several-pull-requests.md)**

> **[Estimate when a queued pull request will merge](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/estimate-when-a-queued-pull-request-will-merge.md)**

### Testing

> **[List a merge queue's verification runs](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/list-a-merge-queues-verification-runs.md)**

> **[List a pull request's verification runs](https://docs.trunk.io/merge-queue/reference/api-v2/pullrequests/list-a-pull-requests-verification-runs.md)**

> **[Get a verification run](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeueverificationruns/get-a-verification-run.md)**

> **[List a merge queue's completed testing](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/list-a-merge-queues-completed-testing.md)**

### Impacted targets

A queue in `graph` mode (**Parallel** in the app) waits for CI to upload the build targets each pull request impacts before testing it. See [Parallel queues](https://docs.trunk.io/merge-queue/optimizations/parallel-queues).

> **[Upload a pull request's impacted targets](https://docs.trunk.io/merge-queue/reference/api-v2/impactedtargets/upload-a-pull-requests-impacted-targets.md)**

> **[Upload impacted targets from GitHub Actions](https://docs.trunk.io/merge-queue/reference/api-v2/github-actions.md)**

### Metrics

These return Prometheus text format with v1's metric names and labels. See [Prometheus metrics](https://docs.trunk.io/merge-queue/administration/metrics.md#prometheus-metrics-endpoint) for the metrics, example queries, and moving a v1 scrape job.

> **[Get Prometheus metrics for every merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-prometheus-metrics-for-every-merge-queue.md)**

> **[Get Prometheus metrics for a merge queue](https://docs.trunk.io/merge-queue/reference/api-v2/mergequeues/get-prometheus-metrics-for-a-merge-queue.md)**

### Repositories

> **[Resolve a repository by its provider URL](https://docs.trunk.io/merge-queue/reference/api-v2/repositories/resolve-a-repository-by-its-provider-url.md)**

> **[Get a repository](https://docs.trunk.io/merge-queue/reference/api-v2/repositories/get-a-repository.md)**
