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

# List a pull request's verification runs

> Lists every verification run that tested this pull request, newest first — including a run it shared with others, which is reported here for each pull request in the batch. `sort` and `direction` are not configurable yet: each accepts only the value this list already uses (`createdAt`, `desc`) and rejects anything else with `400`. `createdAfter` is not served on this endpoint at all and is rejected with `400` whatever the value; the queue's own verification-run list does serve it.



## OpenAPI

````yaml /openapi-v2.json get /v2/pull-requests/{id}/verification-runs
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 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
paths:
  /v2/pull-requests/{id}/verification-runs:
    get:
      tags:
        - pullRequests
      summary: List a pull request's verification runs
      description: >-
        Lists every verification run that tested this pull request, newest first
        — including a run it shared with others, which is reported here for each
        pull request in the batch. `sort` and `direction` are not configurable
        yet: each accepts only the value this list already uses (`createdAt`,
        `desc`) and rejects anything else with `400`. `createdAfter` is not
        served on this endpoint at all and is rejected with `400` whatever the
        value; the queue's own verification-run list does serve it.
      operationId: pullRequests.listVerificationRuns
      parameters:
        - schema:
            type: string
            format: uuid
            description: The pull request's id.
            example: 0f8fad5b-d9cb-469f-a165-70867728950e
          required: true
          description: The pull request's id.
          name: id
          in: path
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
            description: Page size, between 1 and 100.
            example: 25
          required: false
          description: Page size, between 1 and 100.
          name: limit
          in: query
        - schema:
            type: string
            description: >-
              Opaque cursor from a previous response's `nextCursor`. A cursor is
              bound to the operation and filter it was minted for.
            example: AQEKZm9vYmFy
          required: false
          description: >-
            Opaque cursor from a previous response's `nextCursor`. A cursor is
            bound to the operation and filter it was minted for.
          name: cursor
          in: query
        - schema:
            type: boolean
            default: false
            description: >-
              Set true to include `total` in the response. Costs an extra COUNT
              query, so it is off by default.
            example: false
          required: false
          description: >-
            Set true to include `total` in the response. Costs an extra COUNT
            query, so it is off by default.
          name: includeTotal
          in: query
        - schema:
            allOf:
              - $ref: '#/components/schemas/VerificationRunStatus'
              - description: >-
                  One verification-run status. Sending any other value —
                  including a comma-separated list, which is not supported yet —
                  is a `400`.
          required: false
          description: >-
            One verification-run status. Sending any other value — including a
            comma-separated list, which is not supported yet — is a `400`.
          name: status
          in: query
      responses:
        '200':
          description: A page of verification runs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationRunList'
        '400':
          description: '`VALIDATION_FAILED` | `INVALID_CURSOR`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                VALIDATION_FAILED:
                  summary: VALIDATION_FAILED
                  value:
                    error:
                      code: VALIDATION_FAILED
                      message: 'Invalid input: expected string, received undefined'
                INVALID_CURSOR:
                  summary: INVALID_CURSOR
                  value:
                    error:
                      code: INVALID_CURSOR
                      message: Invalid or expired cursor.
        '401':
          description: '`AUTHENTICATION_REQUIRED` | `INVALID_TOKEN`'
          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
        '404':
          description: '`PR_NOT_FOUND`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                PR_NOT_FOUND:
                  summary: PR_NOT_FOUND
                  value:
                    error:
                      code: PR_NOT_FOUND
                      message: Pull request not found
        '429':
          description: '`RATE_LIMIT_EXCEEDED`'
          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 after the Retry-After delay
        '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
components:
  schemas:
    VerificationRunStatus:
      type: string
      enum:
        - inProgress
        - failed
        - cancelled
        - succeeded
      description: >-
        `inProgress` — checks are still running. `succeeded` — every required
        check passed. `failed` — a required check failed, or the run exceeded
        the queue's `testingTimeoutMinutes` (the two are not distinguished
        today). `cancelled` — the engine abandoned the run, typically because
        the entry left the queue or an entry ahead of it failed.
      example: succeeded
    VerificationRunList:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/VerificationRun'
          maxItems: 100
        nextCursor:
          type:
            - string
            - 'null'
          description: >-
            Opaque cursor for the next page, or null on the last page. Pass it
            back verbatim as `cursor`; do not construct or inspect one.
          example: AQEKZm9vYmFy
        hasMore:
          type: boolean
          description: True when another page is available.
          example: true
        total:
          type: integer
          description: >-
            Total rows matching the filter. Present only when the request set
            `includeTotal=true`.
          example: 1247
      required:
        - data
        - nextCursor
        - hasMore
    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 uniform error envelope. Every 4xx and 5xx response in this API has
        this shape.
    VerificationRun:
      type: object
      properties:
        id:
          type: string
          example: a1b2c3d4-e5f6-4718-9a0b-1c2d3e4f5061
        isBisection:
          type: boolean
          description: >-
            True when this run exists to attribute a failed batch to a specific
            entry, rather than to verify new work.
          example: false
        testBranch:
          type: string
          description: The ephemeral branch the queue built to run this verification on.
          example: trunk-merge/01HX3K
        testBranchSha:
          type: string
          example: 1f0a9b8c7d6e5f40312233445566778899aabbcc
        testBranchCommitUrl:
          type: string
          description: >-
            The tested commit on the provider, for a human to open — v1
            publishes this same link as `testBranchUrl`, which addresses the
            commit rather than the branch. Absent for a non-GitHub repository,
            and for a run that never got a tested commit (one cancelled before
            it started).
          example: >-
            https://github.com/acme/widgets/commit/1f0a9b8c7d6e5f40312233445566778899aabbcc
        createdAt:
          type: string
          format: date-time
          description: When the run was created.
          example: '2026-07-28T11:05:00.000Z'
        updatedAt:
          type: string
          format: date-time
          description: >-
            When the run last changed. For a finished run this approximates when
            it concluded; there is no separate `finishedAt` yet.
          example: '2026-07-28T11:35:00.000Z'
        status:
          $ref: '#/components/schemas/VerificationRunStatus'
        requiredStatusesSource:
          $ref: '#/components/schemas/RequiredStatusesSource'
        requiredStatuses:
          type: array
          items:
            type: string
          maxItems: 10000
          description: >-
            Names of the checks that were required for this run, snapshotted
            when it started (resolved from the queue's configured statuses, then
            `.trunk/trunk.yaml`, then the branch's GitHub protection contexts).
            A check in `checks` is required iff its `name` is in this list; the
            checks themselves carry no required flag. Empty means nothing was
            required.
          example:
            - Lint (typescript)
            - Test (rust)
        checks:
          type: array
          items:
            $ref: '#/components/schemas/Check'
          maxItems: 10000
          description: >-
            Every check the run observed, provider check runs and commit
            statuses normalized to one shape. A failure here is the usual reason
            an entry left `testing` for `failed`.
        testedPullRequests:
          type: array
          items:
            $ref: '#/components/schemas/TestedPullRequest'
          maxItems: 10000
          description: >-
            The pull requests included in this run. More than one means the
            entries were batched, so a failure is attributable to any of them
            until bisection narrows it.
        dependentPullRequests:
          type: array
          items:
            $ref: '#/components/schemas/DependentPullRequest'
          maxItems: 10000
          description: >-
            Pull requests whose commits were merged into the test branch to
            build the predicted base, but which this run is not testing. A
            merged-in commit is absent here when it belongs to no pull request
            (a plain base-branch commit) or when that pull request's branch has
            moved since the run, so this list is usually shorter than what the
            run carried. It can also be longer: a commit is matched by
            (repository, sha), which is indexed but not unique, so one merged-in
            commit resolves to every pull request in the repository whose head
            is that sha.
        testBranchPullRequest:
          $ref: '#/components/schemas/TestBranchPullRequest'
        impactedTargets:
          $ref: '#/components/schemas/VerificationRunImpactedTargets'
      required:
        - id
        - isBisection
        - testBranch
        - testBranchSha
        - createdAt
        - updatedAt
        - status
        - requiredStatuses
        - checks
        - testedPullRequests
        - dependentPullRequests
    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
        - 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
    RequiredStatusesSource:
      type: string
      enum:
        - trunkConfig
        - repoProviderBranchProtection
        - mergeInstance
      description: >-
        Where the queue resolved a run's required checks from, in the order it
        tries them: `mergeInstance` — the queue's own configured list;
        `trunkConfig` — `merge.required_statuses` in the repository's
        `.trunk/trunk.yaml`, read off the test branch;
        `repoProviderBranchProtection` — the target branch's protection rules at
        the provider. Absent in two cases: a run recorded before Trunk stored
        the source (before 2024-01-24), and a run cancelled before it started,
        which resolved no statuses at all and carries an empty
        `requiredStatuses` with it. v1 reports both as `trunk_config`, which is
        its merge service's default rather than an observation.
      example: trunkConfig
    Check:
      type: object
      properties:
        id:
          type: string
          example: '31245987'
        name:
          type: string
          example: build
        kind:
          $ref: '#/components/schemas/CheckKind'
        status:
          $ref: '#/components/schemas/CheckStatus'
        conclusion:
          $ref: '#/components/schemas/CheckConclusion'
        providerStatus:
          $ref: '#/components/schemas/ProviderCheckStatus'
        providerConclusion:
          $ref: '#/components/schemas/ProviderCheckConclusion'
        url:
          type:
            - string
            - 'null'
          description: >-
            Link to the check at its provider, for a human to open. Null when
            the provider did not supply one.
          example: https://github.com/acme/widgets/runs/31245987
        provider:
          type: string
          enum:
            - github
          example: github
      required:
        - id
        - name
        - kind
        - status
        - conclusion
        - url
        - provider
      description: >-
        A normalized CI check. Both provider check runs and commit statuses map
        onto this one shape; `kind` says which one this is, and the `provider*`
        fields carry the unfolded values.
    TestedPullRequest:
      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 included in a verification run. When a run covers
        several, a failure is attributable to any of them — that is what
        bisection resolves.
    DependentPullRequest:
      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 commit of this pull request that was merged into the test
            branch. It equals the pull request's stored head by construction —
            the lookup matches on it — so a pull request whose branch moved
            after the run is absent from this list rather than listed with an
            old sha.
          example: 0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d
        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 whose commit was merged into the test branch to form the
        predicted base, but which this run is not testing. Same shape as
        `TestedPullRequest`; the distinction is whether a failure is
        attributable to it.
    TestBranchPullRequest:
      type: object
      properties:
        number:
          type: integer
          example: 5002
        url:
          type: string
          example: https://github.com/acme/widgets/pull/5002
      required:
        - number
        - url
      description: >-
        The pull request or merge request the queue opened for the test branch,
        where its checks and logs are. On GitHub, the pull request the queue
        opened for the test branch, present only when the queue is configured to
        open one. On GitLab, the draft merge request the queue always opens for
        the test branch; `number` is its iid and `url` its web URL, e.g.
        `https://gitlab.com/acme/widgets/-/merge_requests/42`.
    VerificationRunImpactedTargets:
      type: object
      properties:
        all:
          $ref: '#/components/schemas/ImpactedTargetSet'
        testedPullRequestsOnly:
          $ref: '#/components/schemas/ImpactedTargetSet'
      required:
        - all
      description: >-
        The impacted targets uploaded for the run's commits (`PUT
        /impacted-targets`). Returned only when a single run is fetched by ID,
        never in a list, and absent when no commit on the run has an upload.
        `all` spans every commit the run carried: the pull requests under test
        and the commits merged in beneath them to build the predicted base.
        `testedPullRequestsOnly` spans the tested pull requests' commits alone,
        and is absent when none of them uploaded. A commit with no upload
        contributes nothing to either set.
    CheckKind:
      type: string
      enum:
        - checkRun
        - statusCheck
      description: >-
        Which provider entity a check is. `checkRun` is a GitHub check run, with
        its own lifecycle; `statusCheck` is a commit status, which carries a
        state and nothing else. It decides how to read `providerConclusion`.
      example: checkRun
    CheckStatus:
      type: string
      enum:
        - queued
        - inProgress
        - completed
      description: >-
        A check's lifecycle. Only `completed` means `conclusion` is final; for
        `queued` and `inProgress` the conclusion is a placeholder (`neutral`).
      example: completed
    CheckConclusion:
      type: string
      enum:
        - success
        - failure
        - neutral
        - cancelled
        - skipped
        - timeout
      description: >-
        A check's outcome. `neutral` is also the placeholder for a check that
        has not concluded yet.
      example: success
    ProviderCheckStatus:
      type: string
      enum:
        - QUEUED
        - IN_PROGRESS
        - COMPLETED
        - PENDING
        - WAITING
        - REQUESTED
      description: >-
        A check's status as the provider reported it, before normalization,
        uppercased as Trunk stores it — the vocabulary v1 publishes. `WAITING`
        and `PENDING` are the deployment-gate states: a check run in one of them
        is waiting on a manual approval, not running, and the normalized
        `status` reports `QUEUED`, `REQUESTED`, `WAITING` and `PENDING` alike as
        `queued`. Absent on a `statusCheck`, which has no lifecycle of its own,
        and on a check run whose provider set none.
      example: COMPLETED
    ProviderCheckConclusion:
      type: string
      enum:
        - ACTION_REQUIRED
        - CANCELLED
        - ERROR
        - FAILURE
        - NEUTRAL
        - PENDING
        - SKIPPED
        - STALE
        - SUCCESS
        - TIMED_OUT
      description: >-
        The provider's own verdict, before normalization, uppercased as Trunk
        stores it. Read it with `kind`: a `checkRun` uses GitHub's check-run
        conclusions (everything here but `ERROR`), a `statusCheck` its
        commit-status states (`SUCCESS`, `FAILURE`, `ERROR`, `PENDING`). This is
        where the values the normalized `conclusion` cannot express survive — it
        folds `ACTION_REQUIRED` and `STALE` to `neutral`, and `ERROR` to
        `failure` beside a genuine `FAILURE`. Absent when the provider set none.
      example: SUCCESS
    ImpactedTargetSet:
      type: object
      properties:
        impactsAllTargets:
          type: boolean
          description: >-
            True when any commit in this set uploaded `impactsAllTargets: true`,
            which makes the explicit lists of the others moot.
          example: false
        impactedTargets:
          type: array
          items:
            type: string
          maxItems: 100000
          description: >-
            The union of the commits' uploaded targets, sorted and deduplicated.
            Empty when `impactsAllTargets` is true, and also when every upload
            was an explicit empty list — the commits impact nothing. Truncated
            to the first 100,000 targets; `totalImpactedTargets` says whether it
            was.
          example:
            - //lib/db
            - //svc/api
        totalImpactedTargets:
          type: integer
          description: >-
            The size of the union before truncation. 0 when `impactsAllTargets`
            is true.
          example: 2
      required:
        - impactsAllTargets
        - impactedTargets
        - totalImpactedTargets
      description: The impacted targets of a set of commits on a verification run.
  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.

````