> ## Documentation Index
> Fetch the complete documentation index at: https://code.storage/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# repos.files.metadata.list

> Return a recursive file tree together with per-file commit metadata in one request. Each file also includes a derived `type` field for symmetry with `/files`.

The server reads the last commit of each file under `path`, also when the call sends a `limit` or a `cursor`. When those files have more than 50,000 distinct last commits, the call fails with a 429 response, and a retry gets the same response. To list such a tree, send a narrower `path`.

Scope: `git:read` on the repository.



## OpenAPI

````yaml openapi.json GET /api/repos/{repo_name}/files/metadata
openapi: 3.1.0
info:
  description: >-
    The Code Storage HTTP API exposes repository management, Git reads, and
    write workflows over plain HTTPS.


    ## Authentication


    Send a signed JWT in the `Authorization: Bearer <token>` header on every
    request.


    - Organisation-scoped endpoints such as `GET /api/repos` require
    organisation scopes like `org:read`

    - Repository-scoped endpoints require a JWT whose `repo` claim names the
    target repository

    - Write operations require the relevant scope such as `git:write` or
    `repo:write`


    ## Pagination


    List endpoints use cursor-based pagination.


    - `cursor` is an opaque token returned by the previous response

    - `limit` defaults to `20` and is capped per endpoint

    - `has_more` tells you whether another request is available

    - `next_cursor` becomes the next `cursor` value


    ## Paths


    Preferred routes use the shorter `/api/...` form. Legacy `/api/v1/...`
    aliases remain documented where they are still supported and are marked as
    deprecated when a preferred route exists.


    ## Repository names in paths


    - Names containing `/` (or any other character that is not safe in a URL
    path segment) **must** be URL encoded so the value occupies a single path
    segment. For example, `pierre/example` becomes `pierre%2Fexample` and the
    request URL is `/api/repos/pierre%2Fexample/...`.

    - Plain names that contain only URL-safe characters can be sent as-is:
    `/api/repos/dotfiles/...`.

    - The server URL-decodes the value before resolving the repository, so
    double-encoding is not required.


    ## Errors


    Most endpoints return RFC 9457-compatible problem details under
    `application/problem+json`, with a legacy `error` field mirrored from
    `detail`. Each problem body has a stable, snake_case `code`. Branch on
    `code`, not on `detail`. The Error codes section lists the values.


    A `400 Bad Request` response for a request body can name the invalid fields
    in `invalid_params`. Each item has the dotted path of the field in `name`,
    for example `deployment.production_branch`, and the rule that the value
    breaks in `reason`.


    A `429 Too Many Requests` response carries the current IETF `RateLimit`
    service-limit field and `Retry-After`. `RateLimit` reports immediately
    available quota (`r`) and its effective window in seconds (`t`);
    `Retry-After` is the minimum delay and takes precedence. The gateway's
    capacity is dynamic, so it does not advertise a fixed `RateLimit-Policy` on
    successful responses.


    Streaming commit and note workflows may return operation-specific failure
    bodies so callers can inspect partial results, branch state, or workflow
    status without parsing generic error strings.


    ## Error codes


    Each problem body has a stable `code`. Each status has a generic code. A
    specific code replaces it when the caller must take a different action. New
    codes can be added. Treat an unknown code as the generic code for its
    status.


    Generic codes: `bad_request` (400), `unauthorized` (401), `forbidden` (403),
    `not_found` (404), `method_not_allowed` (405), `request_timeout` (408),
    `conflict` (409), `precondition_failed` (412), `payload_too_large` (413),
    `unprocessable_entity` (422), `rate_limited` (429), `request_canceled`
    (499), `internal_error` (500), `not_implemented` (501), `bad_gateway` (502),
    `service_unavailable` (503), `gateway_timeout` (504). Any other status uses
    its status text in snake_case.


    Specific codes:


    - `authentication_unavailable` (403): the server cannot verify credentials
    now; retry.

    - `insufficient_scope` (403): the token does not have a scope that the
    operation requires.

    - `repo_claim_missing` (400): the token has no `repo` claim.

    - `repo_name_mismatch` (400): the request `repo_name` does not match the
    token `repo` claim.

    - `route_not_found` (404): no API route matches the path.

    - `repository_not_found` (404): the repository does not exist or the token
    cannot access it.

    - `repository_deleted` (409): the repository is already deleted.

    - `repository_thawing` (409): the repository is being restored from cold
    storage; retry after `Retry-After`.

    - `sync_in_progress` (409): an upstream sync is in progress; retry.

    - `upstream_already_configured` (409): the repository already has an
    upstream.

    - `branch_not_found` (404): the branch does not exist.

    - `ref_not_found` (404): the ref or revision does not exist.

    - `merge_conflict` (409): the merge has file conflicts.

    - `ref_guard_failed` (409): a ref guard such as `expected_target_sha` does
    not match the ref; `guard` names it and `current_sha` is the commit of the
    ref.

    - `credential_not_found` (404): the Git credential does not exist.

    - `credential_exists` (409): the repository already has a Git credential.

    - `github_app_not_configured` (412): no GitHub App is set up for the
    organization, or the GitHub App of the repository has no usable private key.

    - `github_repository_inaccessible` (412, or the 4xx status from the
    upstream): GitHub does not give access to the upstream repository.

    - `hosting_not_enabled` (403): hosting is not enabled for the organization.

    - `hosting_project_not_found` (404): the repository has no hosting project.

    - `deployment_not_found` (404): the deployment does not exist.

    - `deployment_project_name_in_use` (409): another repository uses the
    hosting project name.

    - `idempotency_key_reused` (422): the idempotency key belongs to a different
    request.
  title: code.storage
  version: 1.0.0
servers:
  - description: Code Storage API host for your organization
    url: https://api.{org}.code.storage
    variables:
      org:
        default: your-org
        description: >-
          The subdomain of your API host. It is usually your organization name.
          The organization settings page in the dashboard shows your exact API
          host.
security: []
tags:
  - description: >-
      Create, inspect, update, delete, and synchronise repositories, including
      upstream pull-sync and generic HTTPS Git credentials for non-GitHub
      upstreams.
    name: Repositories
  - description: Create, delete, list, and compare branches.
    name: Branches
  - description: >-
      Read commit metadata and diffs, or create commits without a local Git
      client.
    name: Commits
  - description: >-
      Read repository trees, file contents, archives, and server-side search
      results.
    name: Files
  - description: List, create, and delete Git tags.
    name: Tags
  - description: Attach and retrieve Git notes for commits or other Git objects.
    name: Notes
  - description: >-
      Read metadata about the Code Storage cluster that serves your
      organisation, such as its cloud location and inbound IP addresses.
    name: Organization
paths:
  /api/repos/{repo_name}/files/metadata:
    get:
      tags:
        - Files
      summary: List Files with Metadata
      description: >-
        Return a recursive file tree together with per-file commit metadata in
        one request. Each file also includes a derived `type` field for symmetry
        with `/files`.


        The server reads the last commit of each file under `path`, also when
        the call sends a `limit` or a `cursor`. When those files have more than
        50,000 distinct last commits, the call fails with a 429 response, and a
        retry gets the same response. To list such a tree, send a narrower
        `path`.


        Scope: `git:read` on the repository.
      operationId: repos-files-metadata-list
      parameters:
        - description: The repository name, for example `acme/web`.
          example: my-demo-repository
          in: path
          name: repo_name
          required: true
          schema:
            type: string
        - description: >-
            Optional branch, tag, or commit SHA to list from. When omitted, the
            repository default branch is used.
          example: main
          in: query
          name: ref
          schema:
            type: string
        - description: >-
            Optional repository-relative subtree to list recursively. Empty
            means the repository root.
          example: docs
          in: query
          name: path
          schema:
            type: string
        - description: >-
            Accepted for API symmetry. Metadata listings are recursive
            regardless of this flag.
          example: true
          in: query
          name: recursive
          schema:
            type: boolean
        - description: >-
            Pagination cursor returned by a previous `list_files_with_metadata`
            response.
          example: docs/guide.md
          in: query
          name: cursor
          schema:
            type: string
        - description: >-
            Maximum number of files to return. A call with no `limit` and no
            `cursor` returns every file in one response, with `has_more` false.
            A `limit` of 0 is the same as no `limit`. A call with a `cursor` and
            no `limit` returns up to 200 files.
          example: 200
          in: query
          name: limit
          schema:
            maximum: 1000
            minimum: 0
            type: integer
        - description: Whether `ref` should be resolved from the ephemeral namespace.
          example: true
          in: query
          name: ephemeral
          schema:
            type: boolean
      responses:
        '200':
          content:
            application/json:
              example:
                files:
                  - last_commit_sha: a1b2c3d4e5f6
                    mode: '100644'
                    path: README.md
                    size: 2048
                    type: blob
                has_more: true
                next_cursor: MTcwNzU3MzQ1MTAwMDAwMDAwMHxyZXBvXzlhNGMyMWY
                ref: main
              schema:
                $ref: '#/components/schemas/ReposFilesMetadataListResponse'
          description: >-
            The repository tree plus deduplicated commit metadata for the latest
            change touching each file.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Bad Request
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Not Found
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Conflict
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Too Many Requests
          headers:
            RateLimit:
              description: >-
                Current IETF service-limit field. `r=0` means no request is
                immediately available; `t` is the effective window in seconds
                before capacity is expected to return.
              schema:
                type: string
            Retry-After:
              description: >-
                Minimum delay before retrying, expressed as seconds or an HTTP
                date. This value takes precedence over the `RateLimit` effective
                window.
              schema:
                type: string
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Internal Server Error
        '503':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Service Unavailable
          headers:
            Retry-After:
              description: Minimum delay in seconds before retrying.
              schema:
                type: string
      security:
        - bearerAuth:
            - git:read
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            import { Pierre } from '@pierre/sdk';

            // The client reads PIERRE_ORG and PIERRE_PRIVATE_KEY.
            const pierre = new Pierre();

            for await (const metadata of pierre.repos.files.metadata.list({
              repo_name: 'my-demo-repository',
              ephemeral: true,
              limit: 200,
              path: 'docs',
              recursive: true,
              ref: 'main',
            })) {
              console.log(metadata);
            }
        - lang: python
          label: Python
          source: |-
            from pierre import Pierre

            # The client reads PIERRE_ORG and PIERRE_PRIVATE_KEY.
            pierre = Pierre()

            for metadata in pierre.repos.files.metadata.list(
                repo_name="my-demo-repository",
                ephemeral=True,
                limit=200,
                path="docs",
                recursive=True,
                ref="main",
            ):
                print(metadata)
        - lang: go
          label: Go
          source: "import (\n\t\"context\"\n\t\"fmt\"\n\n\tpierre \"github.com/pierrecomputer/sdk/go\"\n)\n\nctx := context.Background()\n// The client reads PIERRE_ORG and PIERRE_PRIVATE_KEY.\nclient, err := pierre.NewClient()\nif err != nil {\n\treturn err\n}\npage, err := client.Repos.Files.Metadata.List(ctx, pierre.ReposFilesMetadataListParams{\n\tRepoName:  \"my-demo-repository\",\n\tEphemeral: pierre.Bool(true),\n\tLimit:     pierre.Int(200),\n\tPath:      pierre.String(\"docs\"),\n\tRecursive: pierre.Bool(true),\n\tRef:       pierre.String(\"main\"),\n})\nif err != nil {\n\treturn err\n}\nfor metadata, err := range page.All(ctx) {\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Println(metadata)\n}"
        - lang: cli
          label: CLI
          source: |-
            pierre repos:files:metadata list \
              --repo-name my-demo-repository \
              --ephemeral \
              --limit 200 \
              --path docs \
              --recursive \
              --ref main
        - lang: bash
          label: cURL
          source: |-
            curl \
              "https://api.{org}.code.storage/api/repos/my-demo-repository/files/metadata?ephemeral=true&limit=200&path=docs&recursive=true&ref=main" \
              -H "Authorization: Bearer $PIERRE_TOKEN"
components:
  schemas:
    ReposFilesMetadataListResponse:
      additionalProperties: false
      description: >-
        Files in the repository at the resolved revision, each annotated with
        mode, type, and the latest commit that changed it.
      properties:
        commits:
          additionalProperties:
            $ref: '#/components/schemas/FileLastCommit'
          description: >-
            Commit metadata keyed by last_commit_sha so repeated commits are
            only sent once.
          type: object
        files:
          description: >-
            Files in the resolved revision, each annotated with the latest
            commit that changed it.
          items:
            $ref: '#/components/schemas/FileWithMetadata'
          type: array
        has_more:
          description: Whether another page is available.
          examples:
            - true
          type: boolean
        next_cursor:
          description: >-
            Opaque cursor for the next page. Pass it as `cursor` to read the
            next page. Absent when there are no more results.
          examples:
            - MTcwNzU3MzQ1MTAwMDAwMDAwMHxyZXBvXzlhNGMyMWY
          type: string
        ref:
          description: The resolved ref or commit used to generate the listing.
          examples:
            - main
          type: string
      required:
        - files
        - commits
        - ref
        - has_more
      type: object
    ProblemDetails:
      description: >-
        RFC 9457-compatible problem details payload describing the error
        response.
      properties:
        code:
          description: >-
            A stable, machine-readable error code in snake_case. Branch on
            `code`, not on `detail`. The API description lists the codes.
          type: string
        detail:
          description: >-
            A human-readable explanation specific to this occurrence of the
            problem.
          type: string
        error:
          description: Legacy compatibility field mirroring `detail` for older clients.
          type: string
        instance:
          description: >-
            A URI reference that identifies the specific occurrence of the
            problem.
          type: string
        status:
          description: >-
            The HTTP status code generated by the origin server for this
            occurrence of the problem.
          format: int64
          type: integer
        title:
          description: A short, human-readable summary of the problem type.
          type: string
        type:
          description: >-
            A URI reference that identifies the problem type. `about:blank`
            indicates the generic HTTP status semantics apply.
          type: string
      required:
        - type
        - title
        - status
        - code
      type: object
    FileLastCommit:
      additionalProperties: false
      description: >-
        Commit metadata shared by one or more files in a
        list-files-with-metadata response.
      properties:
        author:
          description: Author display name for the commit.
          examples:
            - Jon Crosby
          type: string
        date:
          description: RFC 3339 author date for the commit.
          examples:
            - '2026-02-18T10:30:00Z'
          type: string
        message:
          description: >-
            The subject line of the commit message: the first paragraph of the
            message as one line, without the body and the trailers.
            repos.commits.get returns the full message.
          examples:
            - add list files with metadata endpoint
          type: string
        order:
          description: >-
            History-order rank relative to the resolved ref: 0 is the commit
            closest to the ref tip (newest in history), larger values are older.
            Derived from a topological walk rather than author dates, so callers
            can rank a folder's latest change by the smallest order among its
            files.
          examples:
            - 0
          format: int32
          type: integer
      required:
        - author
        - date
        - message
        - order
      type: object
    FileWithMetadata:
      additionalProperties: false
      description: >-
        File entry in a list-files-with-metadata response, including mode, type,
        and the SHA of the most recent commit that touched it.
      properties:
        last_commit_sha:
          description: Commit SHA of the most recent commit that touched this file.
          examples:
            - a1b2c3d4e5f6
          type: string
        mode:
          description: File mode as stored in Git, for example 100644.
          examples:
            - '100644'
          type: string
        path:
          description: Repository-relative file path.
          examples:
            - README.md
          type: string
        size:
          description: File size in bytes.
          examples:
            - 2048
          format: int64
          type: integer
        type:
          description: 'Derived file type: blob, tree, symlink, or submodule.'
          examples:
            - blob
          type: string
      required:
        - path
        - mode
        - type
        - size
        - last_commit_sha
      type: object
  securitySchemes:
    bearerAuth:
      bearerFormat: JWT
      description: >-
        JWT bearer token signed with your organization's registered signing key.
        There is no OAuth authorization server; you mint tokens yourself and the
        token's `scopes` claim carries the granted permission scopes. Public
        scopes: `git:read` (read repository contents), `git:write` (write
        branches, commits, tags, and notes), `repo:write` (create and manage
        repositories), `org:read` (list an organization's repositories). Each
        operation's security requirement names the scopes it requires. See
        https://code.storage/docs/getting-started/authentication for how to mint
        tokens.
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.