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

# Get a merge queue's dispatch order

> Returns the queue's batches with a verification run, what is admitted and waiting in the order the engine will consider it, and what has not been admitted yet.

**A batch in `batches` is not necessarily still testing** — one that has passed, is merging, or is holding others back after a failure still has a run and is still listed. Read its `state`.

**The order is one of consideration, not of execution, and array position is not a wait estimate.** `predictedBatch` repeats across every pull request predicted to start testing together, and in `graph` mode several predicted batches commonly start at once — so the pull requests ahead of yours may all start with it, and may sit on unrelated branches that never block yours. `directlyAhead` is what actually precedes a pull request; use it rather than counting.

It is a point-in-time prediction. A new submission, a priority change or a failure regroups it, and four things outside this response still gate dispatch: `queueState: paused` stops it entirely, the queue's testing-concurrency cap bounds how many start, a batch whose predecessors have no usable test branch is skipped over rather than blocking, and bisections dispatch on their own budget.

Pull requests that are not ready are deliberately absent — they are not admitted, so they hold no position. Read one through `GET /v2/pull-requests/{id}`.

Unpaginated: the engine caps its own graph, so the admitted set is bounded. `awaitingAdmission` is not, and is truncated.



## OpenAPI

````yaml /openapi-v2.json get /v2/merge-queues/{id}/order
openapi: 3.1.0
info:
  title: Trunk API
  version: 2.0.0
  description: >-
    The Trunk public API. Every endpoint is scoped to a single organization and
    requires a credential.


    ## Authentication


    For automation, send an API key as `Authorization: Bearer <key>`. An
    organization admin creates one in the Trunk app under **Settings → Developer
    → API Keys**, and chooses the permissions it holds. A key with no
    permissions can read merge queues but change nothing in them. Each write's
    description names the permission it needs, if any. Permissions cover merge
    queues and test-result uploads, including the quarantine lookups a CI run
    makes before it uploads; any key can call the other Flaky Tests and Dynamic
    CI endpoints, including their writes.


    A short-lived token in the `x-trunk-token` header is what Trunk's own tools
    send, such as the `trunk` CLI after `trunk auth login`. Your own
    integrations should use an API key.


    A GitHub Actions job can upload impacted targets with no Trunk secret: the
    `trunk-io/login` action exchanges the run's own GitHub credential (its OIDC
    token, or on a pull request from a fork its `GITHUB_TOKEN`) for a
    short-lived first-party token. That token is accepted only by `PUT
    /v2/impacted-targets`, for the run's own repository — and on a fork pull
    request, only for that pull request and its head sha.


    ## Errors


    Errors from the API are an `ErrorResponse`: `{ "error": { "code", "message"
    } }`. Switch on `code`, which is stable; `message` is prose and may change
    at any time.


    Some responses don't have this shape. Trunk's edge answers `401`, `403` for
    some credential problems (including a request with no credential), `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.


    **An authorization denial on a read is reported as `404`, not `403`** —
    whether a resource exists must not leak across organizations, so a resource
    in another organization is indistinguishable from one that does not exist.
    `403 INSUFFICIENT_PERMISSIONS` means the credential is valid but is not
    permitted the action (or carries no organization).


    Every response from the API carries an `X-Request-Id` header; edge responses
    may not. Quote it in support requests.


    ## Rate limiting


    Most requests share one limit per organization (currently 100 requests per
    second), across every API key, user, and CLI session in it. Some requests
    have limits of their own and don't count toward it: `GET` requests on paths
    that start with `/v2/pull-requests`, `/v2/ci-jobs`, `/v2/ci-workflow-runs`,
    or `/v2/ci-failure-clusters` (5 per second per API key or user); the merge
    queue metrics endpoints (5 per second per organization); impacted-target
    uploads from a GitHub Actions login (10 per second per repository, and
    separately for its fork pull requests); test-result uploads (1000 per second
    per organization) and quarantine lookups (250 per second per organization).
    Exceeding a limit returns `429`; retry with backoff. The limit is enforced
    at the edge, which does not yet wrap its `429` in the `ErrorResponse`
    envelope or send `Retry-After`, so treat any `429` as rate limiting
    regardless of body.


    ## Compatibility


    Within v2, Trunk may add: new endpoints, new **optional** response fields,
    new members to any enum (including new `code` values, new queue-entry
    states, and new providers), and new optional request parameters. **Clients
    must tolerate values and fields they do not recognize** rather than failing
    closed — a client that switches exhaustively over an enum will break when a
    member is added. Removals and semantic changes require a new major version.


    ## Provider support


    Merge queues, verification runs and checks are **GitHub-only** today;
    `Check.provider` has a single member for that reason. `PUT
    /v2/impacted-targets` accepts GitHub and GitLab repositories. A GitHub
    Actions login (the `trunk-io/login` action, or `trunk auth login
    --github-actions`) uploads only for its own GitHub repository. The
    `Provider` enum lists values the repository index can store, not surfaces
    that are fully supported.


    ## Not yet available


    A pull request's numeric **position** in its queue is not exposed, and list
    responses are not ordered by queue position. `GET
    /v2/merge-queues/{id}/order` returns the order the engine will consider pull
    requests in, but an array index there is not a wait: use a pending entry's
    `directlyAhead` rather than counting, and `GET
    /v2/pull-requests/{id}/queue-entry-estimate` for when it is expected to
    merge (on queues that serve estimates). This API delivers no events of its
    own — poll it, or subscribe to [Merge Queue's
    webhooks](https://docs.trunk.io/merge-queue/webhooks). `Idempotency-Key` is
    not yet honored, so a mutation that times out must be reconciled by reading
    the resource back rather than blindly retried.
  contact:
    name: Trunk Support
    url: https://docs.trunk.io
servers:
  - url: https://api.trunk.io
    description: Production
security:
  - apiKey: []
  - trunkToken: []
tags:
  - name: mergeQueues
    x-group: Merge Queues
  - name: pullRequests
    x-group: Pull Requests
  - name: mergeQueueVerificationRuns
    x-group: Verification Runs
  - name: impactedTargets
    x-group: Impacted Targets
  - name: repositories
    x-group: Repositories
  - name: dynamicCi
    x-group: Dynamic CI
  - name: ciJobs
    x-group: CI Jobs
  - name: ciWorkflowRuns
    x-group: CI Workflow Runs
  - name: ciFailureClusters
    x-group: CI Failure Clusters
  - name: testCollections
    x-group: Test Collections
  - name: tests
    x-group: Tests
  - name: testUploads
    x-group: Test Uploads
  - name: detectionEvents
    x-group: Detection Events
paths:
  /v2/merge-queues/{id}/order:
    get:
      tags:
        - mergeQueues
      summary: Get a merge queue's dispatch order
      description: >-
        Returns the queue's batches with a verification run, what is admitted
        and waiting in the order the engine will consider it, and what has not
        been admitted yet.


        **A batch in `batches` is not necessarily still testing** — one that has
        passed, is merging, or is holding others back after a failure still has
        a run and is still listed. Read its `state`.


        **The order is one of consideration, not of execution, and array
        position is not a wait estimate.** `predictedBatch` repeats across every
        pull request predicted to start testing together, and in `graph` mode
        several predicted batches commonly start at once — so the pull requests
        ahead of yours may all start with it, and may sit on unrelated branches
        that never block yours. `directlyAhead` is what actually precedes a pull
        request; use it rather than counting.


        It is a point-in-time prediction. A new submission, a priority change or
        a failure regroups it, and four things outside this response still gate
        dispatch: `queueState: paused` stops it entirely, the queue's
        testing-concurrency cap bounds how many start, a batch whose
        predecessors have no usable test branch is skipped over rather than
        blocking, and bisections dispatch on their own budget.


        Pull requests that are not ready are deliberately absent — they are not
        admitted, so they hold no position. Read one through `GET
        /v2/pull-requests/{id}`.


        Unpaginated: the engine caps its own graph, so the admitted set is
        bounded. `awaitingAdmission` is not, and is truncated.
      operationId: mergeQueues.order
      parameters:
        - schema:
            type: string
            description: The merge queue's id.
            example: xK9mP2nQ
          required: true
          description: The merge queue's id.
          name: id
          in: path
      responses:
        '200':
          description: The queue's dispatch order
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MergeQueueOrder'
        '401':
          description: >-
            `AUTHENTICATION_REQUIRED` | `INVALID_TOKEN`. A malformed, expired,
            or deleted credential. Trunk's edge usually answers this before the
            request reaches the API, with a body that is not this envelope
            (`{"error": "unauthorized: invalid api key"}` for a bad API key, or
            plain text for a bad `x-trunk-token`), so branch on the status. A
            request with no credential at all gets `403` from the edge.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                AUTHENTICATION_REQUIRED:
                  summary: AUTHENTICATION_REQUIRED
                  value:
                    error:
                      code: AUTHENTICATION_REQUIRED
                      message: No credential was supplied
                INVALID_TOKEN:
                  summary: INVALID_TOKEN
                  value:
                    error:
                      code: INVALID_TOKEN
                      message: The supplied token failed verification
        '403':
          description: '`INSUFFICIENT_PERMISSIONS`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                INSUFFICIENT_PERMISSIONS:
                  summary: INSUFFICIENT_PERMISSIONS
                  value:
                    error:
                      code: INSUFFICIENT_PERMISSIONS
                      message: >-
                        The supplied credential is missing the required
                        permission
        '404':
          description: '`MERGE_QUEUE_NOT_FOUND`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                MERGE_QUEUE_NOT_FOUND:
                  summary: MERGE_QUEUE_NOT_FOUND
                  value:
                    error:
                      code: MERGE_QUEUE_NOT_FOUND
                      message: Merge queue not found
        '429':
          description: >-
            `RATE_LIMIT_EXCEEDED`. Trunk's edge answers this, and does not yet
            wrap it in the error envelope or send `Retry-After`: treat any `429`
            as rate limiting, whatever its body, and retry with backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                RATE_LIMIT_EXCEEDED:
                  summary: RATE_LIMIT_EXCEEDED
                  value:
                    error:
                      code: RATE_LIMIT_EXCEEDED
                      message: Rate limit exceeded; retry with backoff
        '500':
          description: '`INTERNAL_ERROR`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                INTERNAL_ERROR:
                  summary: INTERNAL_ERROR
                  value:
                    error:
                      code: INTERNAL_ERROR
                      message: An unexpected error occurred
        '502':
          description: '`UPSTREAM_ERROR`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                UPSTREAM_ERROR:
                  summary: UPSTREAM_ERROR
                  value:
                    error:
                      code: UPSTREAM_ERROR
                      message: An upstream service did not respond
components:
  schemas:
    MergeQueueOrder:
      type: object
      properties:
        mode:
          $ref: '#/components/schemas/MergeQueueMode'
        queueState:
          $ref: '#/components/schemas/MergeQueueState'
        batchingEnabled:
          type: boolean
          description: >-
            Batching is configured. When false every pull request forms its own
            predicted batch, and `directlyAhead` is empty throughout.
          example: true
        isolationResolved:
          type: boolean
          description: >-
            False when an `ISOLATE` batching rule could apply to this queue.
            Resolving those costs one impacted-target lookup per pull request,
            so this read skips it — which can move an isolated pull request into
            an earlier predicted batch, and so earlier in `pending`, than the
            engine will actually consider it.
          example: true
        hasCycle:
          type: boolean
          description: >-
            The queue's graph has a cycle and the engine fell back to a degraded
            ordering. `directlyAhead` and `heldBy` are empty, and a held pull
            request reports as `schedulable`.
          example: false
        batches:
          type: array
          items:
            $ref: '#/components/schemas/OrderedBatch'
          maxItems: 10000
          description: >-
            Batches that have a verification run, in dependency order — a batch
            appears after the batches it builds on, with bisections last. **Not
            start order**, and not all of them are still testing: read each
            batch's `state`.
        pending:
          type: array
          items:
            $ref: '#/components/schemas/OrderedPendingItem'
          maxItems: 10000
          description: >-
            Admitted pull requests, in the order the engine will consider them;
            held ones come after schedulable ones. A `schedulable` entry's index
            **is** the number of admitted, schedulable pull requests the engine
            will consider before it — with batching off that is exactly the
            index — but that is not a wait: see `predictedBatch`.
        awaitingAdmission:
          type: array
          items:
            $ref: '#/components/schemas/QueuedPullRequest'
          maxItems: 10000
          description: >-
            Pull requests past the engine's graph soft cap, which hold no
            position yet. Ordered by a DIFFERENT comparator than `pending`, so
            the two lists are not one sequence, and truncated — see
            `awaitingAdmissionTotal`.
        awaitingAdmissionTotal:
          type: integer
          description: >-
            How many are awaiting admission in total. The engine truncates the
            list, so compare this with `awaitingAdmission.length` to detect it;
            read a specific pull request through `GET /v2/pull-requests/{id}`
            rather than scanning.
          example: 0
      required:
        - mode
        - queueState
        - batchingEnabled
        - isolationResolved
        - hasCycle
        - batches
        - pending
        - awaitingAdmission
        - awaitingAdmissionTotal
      description: >-
        The queue's dispatch order: what is testing, what is admitted and
        waiting, and what has not been admitted. Pull requests that are not
        ready are deliberately absent — they hold no position — and are readable
        through `GET /v2/pull-requests/{id}`.
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              $ref: '#/components/schemas/ErrorCode'
            message:
              type: string
              description: >-
                Human-readable description of what went wrong. Not stable — do
                not parse.
              example: An unexpected error occurred
          required:
            - code
            - message
      required:
        - error
      description: >-
        The error envelope. Every error this API itself returns has this shape,
        except a `413` for a body over 512 KB and a `504` for a request that
        runs past its time limit, which are plain text. Responses from Trunk's
        edge, such as a `401`, a `403` for a missing credential, a `429` or a
        `503`, can arrive before the request reaches the API and may not have
        it, so read `error.code` only when the body is JSON with an `error`
        object.
    MergeQueueMode:
      type: string
      enum:
        - queue
        - graph
      description: >-
        The engine a queue runs. `queue` tests entries in strict arrival order,
        one line. `graph` builds a dependency graph and may test entries
        speculatively in parallel, which merges faster but can require bisection
        to attribute a failure. Changing mode is a real conversion, not a flag
        flip — see `mergeQueues.switchModes`.
      example: queue
    MergeQueueState:
      type: string
      enum:
        - running
        - paused
        - draining
        - switchingModes
      description: >-
        The queue's lifecycle state. `switchingModes` is a transient conversion
        state during which config and mode writes are refused.
      example: running
    OrderedBatch:
      type: object
      properties:
        verificationRunId:
          type: string
          description: >-
            The run testing this batch — pass it to `GET
            /v2/merge-queue-verification-runs/{id}`.
          example: 4f3e2d1c-0b9a-4876-9543-210fedcba987
        state:
          $ref: '#/components/schemas/QueueEntryState'
        isBisection:
          type: boolean
          description: >-
            This batch is a bisection, splitting a failed batch to find the
            culprit. Bisections dispatch on their own concurrency budget, so one
            can start ahead of a lower-numbered `predictedBatch`.
          example: false
        pullRequests:
          type: array
          items:
            $ref: '#/components/schemas/QueuedPullRequest'
          maxItems: 10000
          description: The pull requests this run is testing together.
      required:
        - verificationRunId
        - state
        - isBisection
        - pullRequests
      description: >-
        A batch with a verification run — testing, passed, merging, or holding
        others back after a failure. `state` says which.
    OrderedPendingItem:
      type: object
      properties:
        pullRequest:
          $ref: '#/components/schemas/QueuedPullRequest'
        schedulability:
          $ref: '#/components/schemas/PendingSchedulability'
        predictedBatch:
          type: integer
          description: >-
            1-based, and REPEATS across every pull request predicted to start
            testing together. Absent for a held item, which is excluded from the
            prediction. This is an order of CONSIDERATION, not of execution:
            several predicted batches commonly start at once, so a lower number
            is not a shorter wait.
          example: 1
        directlyAhead:
          type: array
          items:
            $ref: '#/components/schemas/QueuedPullRequest'
          maxItems: 10000
          description: >-
            The pull requests immediately in front of this one in the queue's
            graph. Reduced-DAG adjacency, not a conflict set: edges encode
            impacted-target overlap, so an indirect overlap is represented
            through the item between them. Empty when `batchingEnabled` is false
            or `hasCycle` is true.
        heldBy:
          type: array
          items:
            $ref: '#/components/schemas/QueuedPullRequest'
          maxItems: 10000
          description: >-
            The failing pull requests holding this one back, when
            `schedulability` is `heldBehindFailure`.
      required:
        - pullRequest
        - schedulability
        - directlyAhead
        - heldBy
      description: A pull request admitted to the queue but not yet testing.
    QueuedPullRequest:
      type: object
      properties:
        id:
          type: string
          description: >-
            The pull request's id in this API — pass it to `GET
            /v2/pull-requests/{id}`.
          example: 6f1d2c3b-4a59-4e6f-8a7b-9c0d1e2f3a4b
        number:
          type: integer
          example: 4901
        sha:
          type: string
          description: >-
            The head commit that was included in this run. Compare with the pull
            request's current `sha` to detect that its branch moved since.
          example: 9c58bf40e5c1a2b3d4e5f60718293a4b5c6d7e8f
        title:
          type: string
          example: Add the widget endpoint
        url:
          type: string
          description: >-
            The pull request on its provider. Absent until Trunk's sync has
            populated it.
          example: https://github.com/acme/widgets/pull/4901
      required:
        - id
        - number
        - sha
        - title
      description: A pull request in the queue's dispatch order.
    ErrorCode:
      type: string
      enum:
        - AUTHENTICATION_REQUIRED
        - INVALID_TOKEN
        - INSUFFICIENT_PERMISSIONS
        - INTERNAL_ERROR
        - VALIDATION_FAILED
        - NOT_FOUND
        - INVALID_CURSOR
        - MERGE_QUEUE_NOT_FOUND
        - PR_ALREADY_ENQUEUED
        - PR_NOT_ENQUEUEABLE
        - UPSTREAM_ERROR
        - VERIFICATION_RUN_NOT_FOUND
        - PR_NOT_FOUND
        - REPOSITORY_NOT_FOUND
        - IMPACTED_TARGETS_UNSUPPORTED
        - QUEUE_ALREADY_EXISTS
        - QUEUE_HAS_ACTIVE_ENTRIES
        - MODE_CHANGE_IN_PROGRESS
        - PR_NOT_IN_ACTIVE_STATE
        - MERGE_QUEUE_NOT_CREATABLE
        - PR_TESTS_NOT_RESTARTABLE
        - ALLOWED_BOT_SUBMITTERS_FROZEN
        - ESTIMATE_NOT_ENABLED
        - PROVIDER_URL_NOT_FOUND
        - CI_HOST_UNSUPPORTED
        - CI_SCOPE_NOT_FOUND
        - CI_JOB_NOT_FOUND
        - CI_FAILURE_CLUSTER_NOT_FOUND
        - TEST_COLLECTION_NOT_FOUND
        - TEST_NOT_FOUND
        - TEST_UPLOAD_NOT_FOUND
        - OUT_OF_RANGE
        - TICKETING_NOT_CONFIGURED
        - TICKETING_CREDENTIALS_INVALID
        - TICKETING_SITE_REFUSED
        - TICKET_NOT_FOUND
        - TICKET_LINK_CONFLICT
        - TEST_ALREADY_LINKED
        - TICKET_FIELDS_REJECTED
        - TICKET_CONTENT_UNAVAILABLE
        - TICKETING_CREATE_REFUSED
        - RATE_LIMIT_EXCEEDED
      description: >-
        Stable machine-readable error identifier. Switch on this, never on
        `message`. A shipped code's meaning never changes, but **new codes may
        be added within v2** — treat an unrecognized code as a generic failure
        of its HTTP status rather than failing closed.
      example: INTERNAL_ERROR
    QueueEntryState:
      type: string
      enum:
        - notReady
        - pending
        - testing
        - testsPassed
        - merged
        - failed
        - cancelled
        - pendingFailure
      description: >-
        Where a pull request sits in its queue's lifecycle.


        | Value | Meaning |

        | --- | --- |

        | `notReady` | Enqueued but not yet eligible to test — a readiness
        condition is unmet (see `QueueEntry.readiness`). |

        | `pending` | Ready and waiting for a test slot, or waiting on an
        earlier entry. |

        | `testing` | A verification run is in flight for this entry. |

        | `testsPassed` | Verification succeeded; waiting to merge. |

        | `merged` | Terminal — merged into the target branch. |

        | `failed` | Terminal — verification or the merge itself failed. |

        | `cancelled` | Terminal — removed from the queue (dequeued, or
        cancelled by the engine). |

        | `pendingFailure` | This entry's tests failed, and the queue is holding
        it to learn whether the failure is its own: it waits for the entries
        ahead of it to finish, and a passing run behind it can vouch for it. Not
        terminal: it can still pass and merge, return to `pending` or `testing`,
        or end `failed`. |


        New members may be added within v2.
      example: testing
    PendingSchedulability:
      type: string
      enum:
        - schedulable
        - heldBehindFailure
      description: >-
        `schedulable` means eligible for the next scheduling pass, NOT that it
        will run next — the pass is still gated by `queueState`, the queue's
        testing-concurrency cap, and predecessors lacking a usable test branch.
        `heldBehindFailure` means a `PENDING_FAILURE` ancestor is holding it;
        `heldBy` names which.
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        An API key, sent as `Authorization: Bearer <key>`. An organization admin
        creates one in the Trunk app under **Settings → Developer → API Keys**
        and chooses the permissions it holds. A key with none can read merge
        queues but change nothing in them. Permissions cover merge queues and
        test-result uploads, including the quarantine lookups a CI run makes
        before it uploads; any key can call the other Flaky Tests and Dynamic CI
        endpoints, including their writes.
    trunkToken:
      type: apiKey
      in: header
      name: x-trunk-token
      description: >-
        A short-lived token that Trunk's own tools send in the `x-trunk-token`
        header: the `trunk` CLI after `trunk auth login`, and the
        `trunk-io/login` action in a GitHub Actions run. Your own integrations
        should use an API key instead. Never send `Authorization` and
        `x-trunk-token` on the same request.


        **A token from a GitHub Actions run can only upload impacted targets**
        (`PUT /v2/impacted-targets`), for the repository the run belongs to;
        every other endpoint refuses it.

````