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

# Automate the queue with the API

> Submit pull requests, wait for merges, and read queue order with the API.

This page shows how to drive a merge queue from your own scripts and CI with the [Trunk API](https://docs.trunk.io/api.md). For authentication, errors, pagination, and rate limits, see the API reference's Getting started pages. Each endpoint has its own page in the API reference.

## 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/api/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

Send an [API key](https://docs.trunk.io/api/authentication#api-keys) as `Authorization: Bearer <key>`. A key with no permissions can read merge queues but can't change them. Writes need the [Merge Queue permissions](https://docs.trunk.io/api/authentication#permissions) listed on each step below.

A GitHub Actions job that uploads impacted targets can [authenticate without a key](https://docs.trunk.io/merge-queue/optimizations/parallel-queues/github-actions.md).

## Finding IDs

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

1. **Queue:** [`GET /v2/merge-queues`](https://docs.trunk.io/api/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/api/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/api/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/api/authentication#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/api/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/api/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/api/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/api/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/api/mergequeueverificationruns/get-a-verification-run.md) and its `checks`.

## Queue order

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/api/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`.

## Retrying

Writes don't honor `Idempotency-Key` yet. A write that times out or returns a `5xx` has an unknown outcome, so read the resource back before you retry it. 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. See [Status codes and errors](https://docs.trunk.io/api/errors.md#retrying).
