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

# Resolve a repository by its provider URL

> Looks up the repositories a provider URL names, scoped to your organization. A `.git` suffix and trailing slashes are normalized away, so every spelling of the same repository resolves alike and shares a cursor.

An unparseable `providerUrl` and a genuine empty result both answer `PROVIDER_URL_NOT_FOUND`, deliberately: a caller must not be able to distinguish a malformed URL from a repository that exists outside their organization. There is no endpoint that enumerates an organization's repositories, so this is the way to resolve one you can name. If you are heading for a merge queue, `GET /v2/merge-queues` needs no arguments and returns every queue in your organization already carrying `repositoryId`, `repositoryUrl` and `targetBranch` — one call rather than two.



## OpenAPI

````yaml /openapi-v2.json get /v2/repositories
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/repositories:
    get:
      tags:
        - repositories
      summary: Resolve a repository by its provider URL
      description: >-
        Looks up the repositories a provider URL names, scoped to your
        organization. A `.git` suffix and trailing slashes are normalized away,
        so every spelling of the same repository resolves alike and shares a
        cursor.


        An unparseable `providerUrl` and a genuine empty result both answer
        `PROVIDER_URL_NOT_FOUND`, deliberately: a caller must not be able to
        distinguish a malformed URL from a repository that exists outside their
        organization. There is no endpoint that enumerates an organization's
        repositories, so this is the way to resolve one you can name. If you are
        heading for a merge queue, `GET /v2/merge-queues` needs no arguments and
        returns every queue in your organization already carrying
        `repositoryId`, `repositoryUrl` and `targetBranch` — one call rather
        than two.
      operationId: repositories.resolveByProviderUrl
      parameters:
        - 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:
            type: string
            minLength: 1
            description: >-
              The repository's URL on its provider. A `.git` suffix and trailing
              slashes are normalized away.
            example: https://github.com/acme/widgets
          required: true
          description: >-
            The repository's URL on its provider. A `.git` suffix and trailing
            slashes are normalized away.
          name: providerUrl
          in: query
      responses:
        '200':
          description: A page of repositories
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RepositoryList'
        '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
        '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: '`PROVIDER_URL_NOT_FOUND`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                PROVIDER_URL_NOT_FOUND:
                  summary: PROVIDER_URL_NOT_FOUND
                  value:
                    error:
                      code: PROVIDER_URL_NOT_FOUND
                      message: No repository found for the requested provider URL
        '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:
    RepositoryList:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Repository'
          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.
    Repository:
      type: object
      properties:
        id:
          type: string
          example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
        provider:
          $ref: '#/components/schemas/Provider'
        path:
          type: string
          description: The provider-side path, `owner/repo`.
          example: acme/widgets
        host:
          type:
            - string
            - 'null'
          description: Null for a repository on the provider's default host.
          example: github.com
        url:
          type: string
          example: https://github.com/acme/widgets
        defaultBranch:
          type:
            - string
            - 'null'
          description: Null until Trunk has synced it.
          example: main
        isPrivate:
          type:
            - boolean
            - 'null'
          description: Null until Trunk has synced it.
          example: true
        createdAt:
          type: string
          format: date-time
          example: '2026-01-14T09:12:00.000Z'
        updatedAt:
          type: string
          format: date-time
          example: '2026-07-20T16:44:10.000Z'
      required:
        - id
        - provider
        - path
        - host
        - url
        - defaultBranch
        - isPrivate
        - createdAt
        - updatedAt
    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
    Provider:
      type: string
      enum:
        - github
        - gitlab
        - bitbucket
        - unknown
      description: >-
        The hosting provider. `unknown` is a repository Trunk has indexed
        without resolving a provider.
      example: github
  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.

````