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

# Update a merge queue's configuration

> Applies a JSON Merge Patch to the queue's configuration: an absent key leaves that setting unchanged, and an unknown key is rejected rather than silently dropped. Send `requiredStatuses: []`, `allowedBotSubmitters: []` or `batchingRules: []` to clear those lists.

**Two of these fields are merge-protection controls, not tuning knobs**: `requiredStatuses` decides what must pass before an entry may merge (clearing it gates on nothing), and `allowedBotSubmitters` decides which bots may enqueue. Treat access to this endpoint as security-relevant. Refused with `MODE_CHANGE_IN_PROGRESS` while the queue is converting between modes.



## OpenAPI

````yaml /openapi-v2.json patch /v2/merge-queues/{id}/config
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 merge-queue permissions it holds. A key with
    no permissions can read merge queues but change nothing. Those permissions
    scope merge queue only: every key can use the Flaky Tests and Dynamic CI
    endpoints, including their writes, whatever permissions it holds.


    A short-lived first-party token in the `x-trunk-token` header is what the
    `trunk` CLI sends after `trunk auth login`.


    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


    Every 4xx and 5xx response is a `ErrorResponse`: `{ "error": { "code",
    "message" } }`. Switch on `code`, which is stable; `message` is prose and
    may change at any time.


    **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 carries an `X-Request-Id` header. Quote it in support
    requests.


    ## Rate limiting


    Requests are limited per organization (currently 100 requests/second).
    Exceeding it returns `429` with `RATE_LIMIT_EXCEEDED`; retry with backoff.
    Note that the limit is enforced at the edge, which does not yet wrap its
    `429` in the `ErrorResponse` envelope described above — 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. Impacted-target
    uploads additionally require a `github.com` repository named `owner/repo`.
    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, and any wait estimate,
    are 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. 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
paths:
  /v2/merge-queues/{id}/config:
    patch:
      tags:
        - mergeQueues
      summary: Update a merge queue's configuration
      description: >-
        Applies a JSON Merge Patch to the queue's configuration: an absent key
        leaves that setting unchanged, and an unknown key is rejected rather
        than silently dropped. Send `requiredStatuses: []`,
        `allowedBotSubmitters: []` or `batchingRules: []` to clear those lists.


        **Two of these fields are merge-protection controls, not tuning knobs**:
        `requiredStatuses` decides what must pass before an entry may merge
        (clearing it gates on nothing), and `allowedBotSubmitters` decides which
        bots may enqueue. Treat access to this endpoint as security-relevant.
        Refused with `MODE_CHANGE_IN_PROGRESS` while the queue is converting
        between modes.
      operationId: mergeQueues.updateConfig
      parameters:
        - schema:
            type: string
            description: The merge queue's id.
            example: xK9mP2nQ
          required: true
          description: The merge queue's id.
          name: id
          in: path
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMergeQueueConfigRequest'
      responses:
        '200':
          description: The updated merge queue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MergeQueue'
        '400':
          description: '`VALIDATION_FAILED`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: '`AUTHENTICATION_REQUIRED` | `INVALID_TOKEN`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`INSUFFICIENT_PERMISSIONS`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: '`MERGE_QUEUE_NOT_FOUND`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: '`MODE_CHANGE_IN_PROGRESS`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: '`ALLOWED_BOT_SUBMITTERS_FROZEN`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: '`RATE_LIMIT_EXCEEDED`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: '`INTERNAL_ERROR`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: '`UPSTREAM_ERROR`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    UpdateMergeQueueConfigRequest:
      type: object
      properties:
        concurrency:
          type: integer
          minimum: 1
          maximum: 1000
        bisectionConcurrency:
          type: integer
          minimum: 0
          maximum: 1000
        pendingFailureDepth:
          type: integer
          minimum: 0
          maximum: 1000
        canOptimisticallyMerge:
          type: boolean
        allowBatching:
          type: boolean
        batchingMaxWaitTimeMinutes:
          type: integer
          minimum: 0
          maximum: 10080
        batchingMinSize:
          type: integer
          minimum: 1
          maximum: 1000
        testingTimeoutMinutes:
          type: integer
          minimum: 0
          maximum: 10080
        notReadyTimeoutMinutes:
          type: integer
          minimum: 0
          maximum: 43200
        createsPrsForTestingBranches:
          type: boolean
        areCommentsEnabled:
          type: boolean
        areCommandsEnabled:
          type: boolean
        isStatusCheckEnabled:
          type: boolean
        isExtensionEnabled:
          type: boolean
        areLabelCommandsEnabled:
          type: boolean
        areStateLabelsEnabled:
          type: boolean
        requiredStatuses:
          type: array
          items:
            type: string
            minLength: 1
          maxItems: 100
        allowedBotSubmitters:
          type: array
          items:
            type: string
            minLength: 1
          maxItems: 100
        batchingRules:
          type: array
          items:
            type: object
            properties:
              targetPattern:
                type: string
              policy:
                type: string
                enum:
                  - isolate
            required:
              - targetPattern
              - policy
          maxItems: 100
        directMergeMode:
          type: string
          enum:
            - 'off'
            - always
        optimizationMode:
          type: string
          enum:
            - 'off'
            - bisectionSkipRedundantTests
        mergeMethod:
          type: string
          enum:
            - mergeCommit
            - squash
            - rebase
        testBranchConstructionMode:
          type: string
          enum:
            - renameTempBranch
            - pushNewBranchFromTemp
        enqueueingLabel:
          type: string
          minLength: 1
      additionalProperties: false
      description: >-
        A JSON Merge Patch: an absent key leaves that setting unchanged, and an
        unknown key is rejected rather than dropped. `requiredStatuses: []`,
        `allowedBotSubmitters: []` and `batchingRules: []` clear those lists. A
        `batchingRules` write replaces the whole set. `notReadyTimeoutMinutes`
        must be a whole number of hours.
    MergeQueue:
      type: object
      properties:
        id:
          type: string
          example: xK9mP2nQ
        repositoryId:
          type: string
          description: Resolve with `GET /v2/repositories/{id}`.
          example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
        targetBranch:
          type: string
          example: main
        state:
          $ref: '#/components/schemas/MergeQueueState'
        mode:
          $ref: '#/components/schemas/MergeQueueMode'
        managedState:
          $ref: '#/components/schemas/ManagedState'
        createdAt:
          type: string
          format: date-time
          description: When the queue was created.
          example: '2026-07-24T20:26:04.000Z'
        updatedAt:
          type: string
          format: date-time
          description: >-
            When the queue's own record last changed — its state or
            configuration. Not affected by entries moving through it.
          example: '2026-07-28T11:02:31.000Z'
        repositoryUrl:
          type: string
          description: >-
            Absolute browsable URL of the repository at its provider (not a
            Trunk API URL).
          example: https://github.com/acme/widgets
        pullRequestsUrl:
          type: string
          description: >-
            Path — **not** an absolute URL — of this queue's pull-request
            collection on the Trunk API. Resolve it against the server URL; do
            not fetch it as-is.
          example: /v2/merge-queues/xK9mP2nQ/pull-requests
        htmlUrl:
          type: string
          description: >-
            The queue's page in the Trunk web app. Absent when the repository
            has no keyed organization (no slug to address it by).
          example: https://app.trunk.io/acme/merge-queue/xK9mP2nQ
        config:
          $ref: '#/components/schemas/MergeQueueConfig'
      required:
        - id
        - repositoryId
        - targetBranch
        - state
        - mode
        - managedState
        - createdAt
        - updatedAt
        - repositoryUrl
        - pullRequestsUrl
        - config
    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: No merge queue found with ID xK9mP2nQ
          required:
            - code
            - message
      required:
        - error
      description: >-
        The uniform error envelope. Every 4xx and 5xx response in this API has
        this shape.
    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
    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
    ManagedState:
      type: string
      enum:
        - manual
        - terraform
        - terraformWithDrift
      description: >-
        Who owns the queue's configuration. `terraform` — the last write came
        from Terraform, identified on any queue write (create, config,
        pause/resume/drain, mode switch) by a `User-Agent` or `X-Source` header
        containing `terraform` or `opentofu`, case-insensitively — the same rule
        as v1. `terraformWithDrift` — Terraform owned it and a later write was
        not identified as Terraform's, so the live configuration may differ from
        the plan. Any such write counts, including pause/resume from other
        automation. `manual` — never written by Terraform.
    MergeQueueConfig:
      type: object
      properties:
        concurrency:
          type: integer
          description: >-
            How many entries the queue may verify at once. Higher values merge
            faster and cost more CI.
          example: 5
        bisectionConcurrency:
          type: integer
          description: >-
            How many verification runs the engine may use in parallel when
            bisecting a failed batch. `0` means bisection gets no dedicated
            capacity and shares `concurrency`.
          example: 0
        pendingFailureDepth:
          type: integer
          description: >-
            How many entries behind a failing entry are pre-emptively marked
            `pendingFailure` rather than continuing to test against a state that
            is expected to fail. `0` disables this.
          example: 3
        canOptimisticallyMerge:
          type: boolean
          description: >-
            Whether an entry whose own verification passed may merge before
            every entry ahead of it has merged, when the engine can prove the
            result still holds.
          example: true
        allowBatching:
          type: boolean
          description: >-
            Whether the queue may verify several entries together in one run.
            Batching is cheaper but a failure must then be attributed by
            bisection. An individual entry can opt out at submit time; the queue
            setting is the ceiling, so an entry cannot batch when this is
            `false`.
          example: false
        batchingMaxWaitTimeMinutes:
          type: integer
          description: >-
            How long the queue waits for more entries before starting a batch
            smaller than `batchingMinSize`. `0` means never wait — start as soon
            as there is anything to test.
          example: 10
        batchingMinSize:
          type: integer
          description: >-
            The batch size the queue prefers before starting a run, subject to
            `batchingMaxWaitTimeMinutes`. At least 1.
          example: 2
        testingTimeoutMinutes:
          type: integer
          description: >-
            How long a verification run may take before the queue abandons it
            and fails the entry. **`0` means no timeout** — a stuck run will
            hold its slot indefinitely.
          example: 60
        notReadyTimeoutMinutes:
          type: integer
          description: >-
            How long an entry may sit `notReady` before the queue cancels it
            (`NOT_READY_TIMEOUT_EXPIRED`). **`0` means no timeout.** Stored as
            whole hours, so this must be a multiple of 60.
          example: 120
          multipleOf: 60
        createsPrsForTestingBranches:
          type: boolean
          description: >-
            Whether the queue opens a provider pull request for each testing
            branch it creates. Makes runs visible in the provider UI at the cost
            of extra pull-request noise.
          example: false
        areCommentsEnabled:
          type: boolean
          description: >-
            Whether the queue posts status comments on pull requests it
            processes.
          example: true
        areCommandsEnabled:
          type: boolean
          description: >-
            Whether the queue acts on comment commands (e.g. a comment asking to
            enqueue or dequeue).
          example: true
        isStatusCheckEnabled:
          type: boolean
          description: >-
            Whether the queue publishes its own status check onto each pull
            request, so its state is visible in the provider's merge box.
          example: true
        isExtensionEnabled:
          type: boolean
          description: >-
            Whether Trunk's browser extension surfaces queue controls on this
            repository's pull requests.
          example: false
        areLabelCommandsEnabled:
          type: boolean
          description: >-
            Whether applying `enqueueingLabel` to a pull request submits it to
            this queue.
          example: true
        areStateLabelsEnabled:
          type: boolean
          description: >-
            Whether the queue maintains labels reflecting each entry's state.
            Trunk owns labels prefixed `trunk-`, which is why `enqueueingLabel`
            may not collide with that prefix.
          example: true
        requiredStatuses:
          type: array
          items:
            type: string
          maxItems: 100
          description: >-
            The provider check names that must pass for an entry to be
            considered verified. **Empty means the queue gates on nothing** — an
            entry passes verification without any check succeeding.
            Security-relevant: this is the queue's merge gate.
          example:
            - build
            - lint
        allowedBotSubmitters:
          type: array
          items:
            type: string
          maxItems: 100
          description: >-
            Bot accounts permitted to submit to this queue in addition to human
            users. Empty means no bots may submit. Security-relevant: this is
            who may enqueue.
          example:
            - dependabot
        batchingRules:
          type: array
          items:
            $ref: '#/components/schemas/BatchingRule'
          maxItems: 100
          description: >-
            Rules changing how pull requests are batched based on the build
            targets they impact. Empty means every entry batches normally.
            Applies to queues in `graph` mode that upload impacted targets.
          example:
            - targetPattern: //db/migrations:*
              policy: isolate
        directMergeMode:
          $ref: '#/components/schemas/DirectMergeMode'
        optimizationMode:
          $ref: '#/components/schemas/OptimizationMode'
        mergeMethod:
          $ref: '#/components/schemas/MergeMethod'
        testBranchConstructionMode:
          $ref: '#/components/schemas/TestBranchConstructionMode'
        enqueueingLabel:
          type: string
          description: >-
            The label that submits a pull request to this queue when
            `areLabelCommandsEnabled` is true. May not collide with a
            Trunk-reserved `trunk-*` state label.
          example: trunk-merge
      required:
        - concurrency
        - bisectionConcurrency
        - pendingFailureDepth
        - canOptimisticallyMerge
        - allowBatching
        - batchingMaxWaitTimeMinutes
        - batchingMinSize
        - testingTimeoutMinutes
        - notReadyTimeoutMinutes
        - createsPrsForTestingBranches
        - areCommentsEnabled
        - areCommandsEnabled
        - isStatusCheckEnabled
        - isExtensionEnabled
        - areLabelCommandsEnabled
        - areStateLabelsEnabled
        - requiredStatuses
        - allowedBotSubmitters
        - batchingRules
        - directMergeMode
        - optimizationMode
        - mergeMethod
        - testBranchConstructionMode
        - enqueueingLabel
      description: >-
        A queue's full configuration. Two fields are merge-protection controls
        rather than tuning knobs — `requiredStatuses` (what must pass) and
        `allowedBotSubmitters` (who may enqueue) — so treat write access to this
        object as security-relevant.
    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
        - 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
        - TICKETING_NOT_CONFIGURED
        - TICKETING_CREDENTIALS_INVALID
        - TICKET_NOT_FOUND
        - TICKET_LINK_CONFLICT
        - 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: MERGE_QUEUE_NOT_FOUND
    BatchingRule:
      type: object
      properties:
        targetPattern:
          type: string
          description: >-
            The impacted-target label this rule applies to. Matched exactly, or
            as a prefix when it ends in a single `*`. A `*` anywhere other than
            the last character is rejected, as is `*` alone — a rule matching
            every target is a queue-wide setting rather than a rule.
          example: //db/migrations:*
        policy:
          $ref: '#/components/schemas/BatchingRulePolicy'
      required:
        - targetPattern
        - policy
      description: >-
        A rule that changes how a pull request is batched based on the build
        targets it impacts. Evaluated from the impacted targets uploaded for the
        pull request's head commit each time the queue forms batches, so it
        follows pushes that add or remove a matching target. A pull request that
        reports impacting all targets matches no rule.
    DirectMergeMode:
      type: string
      enum:
        - 'off'
        - always
      description: >-
        Whether an entry may bypass queue testing and merge directly when the
        target branch is already at its tested state. `off` always tests through
        the queue; `always` merges directly whenever it is safe to do so.
      example: 'off'
    OptimizationMode:
      type: string
      enum:
        - 'off'
        - bisectionSkipRedundantTests
      description: >-
        Whether the engine may skip work it can prove is redundant. `off` runs
        every verification. `bisectionSkipRedundantTests` applies while a failed
        batch is being bisected: a combination of pull requests that has already
        failed is not tested again, and that failure is reused, so an entry can
        reach `failed` (`TEST_RUN_FAILED_BY_OPTIMIZATION`) without a run of its
        own. If that does not yet show which pull request caused it, its pull
        requests are re-tested straight away, alongside the rest of the
        bisection. It never passes an entry without a run.
      example: 'off'
    MergeMethod:
      type: string
      enum:
        - mergeCommit
        - squash
        - rebase
      description: >-
        How the queue writes a passing entry onto the target branch: a merge
        commit, a single squashed commit, or replayed commits. Must be permitted
        by the repository's own provider settings.
      example: squash
    TestBranchConstructionMode:
      type: string
      enum:
        - renameTempBranch
        - pushNewBranchFromTemp
      description: >-
        How the queue turns the temporary branch it builds into the
        `trunk-merge` branch CI runs on. `renameTempBranch` renames the ref.
        `pushNewBranchFromTemp` creates the final ref at the temporary branch's
        head commit and deletes the temporary ref, which needs no rename
        permission — use it when an organization- or enterprise-level ruleset
        targets these branches, since GitHub's rename restriction is the one
        rule an exempt bypass actor cannot lift.
      example: renameTempBranch
    BatchingRulePolicy:
      type: string
      enum:
        - isolate
      description: >-
        What the queue does with a pull request whose impacted targets match the
        rule. `isolate` tests it on its own rather than in a batch, exactly as
        `/trunk merge --no-batch` does.
      example: isolate
  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 merge-queue permissions it holds; a key with none can
        read merge queues but change nothing. Those permissions scope merge
        queue only: every key can use the Flaky Tests and Dynamic CI endpoints,
        including their writes, whatever permissions it holds.
    trunkToken:
      type: apiKey
      in: header
      name: x-trunk-token
      description: >-
        A short-lived first-party token, sent in the `x-trunk-token` header. The
        `trunk` CLI sends one after `trunk auth login`, and the `trunk-io/login`
        action obtains one for a GitHub Actions run.


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

````