{
  "openapi": "3.1.0",
  "info": {
    "title": "uploads.sh API",
    "version": "1.0.0",
    "description": "Workspace-scoped file hosting for agents and humans. The canonical public hierarchy is `/v1/workspaces/{workspace}/...`. Full narrative docs: https://github.com/buildinternet/uploads/blob/main/docs/api.md",
    "contact": {
      "url": "https://github.com/buildinternet/uploads"
    },
    "license": {
      "name": "Apache-2.0",
      "url": "https://github.com/buildinternet/uploads/blob/main/LICENSE"
    }
  },
  "servers": [
    {
      "url": "https://api.uploads.sh",
      "description": "Production API"
    }
  ],
  "tags": [
    {
      "name": "Maintenance",
      "description": "Advanced workspace operations that can scan or delete stored objects."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/public/feeds/{feedId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/FeedId"
        }
      ],
      "get": {
        "operationId": "getPublicFeed",
        "summary": "Read a public change feed",
        "description": "Returns the public newest-first screenshot list for a feed. It omits workspace ownership and object keys. Items are resolved at view time from `gh.repo` and optional `gh.number` metadata.",
        "security": [],
        "responses": {
          "200": {
            "description": "The public feed and its current items."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "503": {
            "description": "Feed storage is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/public/galleries/{galleryId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/GalleryId"
        }
      ],
      "get": {
        "operationId": "getPublicGallery",
        "summary": "Read a public gallery",
        "description": "Returns the public allowlisted projection. It omits workspace ownership and object keys.",
        "security": [],
        "responses": {
          "200": {
            "description": "The public gallery and its public item projection."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "503": {
            "description": "Gallery storage is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "listFiles",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "List workspace files",
        "parameters": [
          {
            "$ref": "#/components/parameters/Prefix"
          },
          {
            "name": "delimiter",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Return common prefixes for folder-style navigation."
          },
          {
            "$ref": "#/components/parameters/FileLimit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of files and an opaque continuation cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/search": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "searchFiles",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Search workspace files",
        "description": "Requires at least one `meta.<key>` equality filter or a `name` substring. Metadata filter names are dynamic query parameters.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          },
          {
            "$ref": "#/components/parameters/Prefix"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A bounded page. `truncated` is true and `cursor` is non-null when more matches remain; pass `cursor` back to continue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileSearch"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/facets": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "listFileFacets",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "List metadata keys or values",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "When present, list values for this metadata key. Otherwise list keys."
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata key facets or value facets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileFacets"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/sign": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "post": {
        "operationId": "signFileUpload",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Create a presigned upload",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Presigned upload details."
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/by-path": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "listFilesByPath",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Group workspace files by GitHub path",
        "description": "Powers the web Screenshots page's grouped-by-path view. Groups recently uploaded `gh.*`-tagged files by project and path.",
        "parameters": [
          {
            "name": "merged",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Set to `1` to include only files tagged from a merged PR."
          }
        ],
        "responses": {
          "200": {
            "description": "Path groups, a flat catalog, known projects, and a flat recent feed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileByPath"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/file-url": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "getFileUrl",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Resolve a usable URL for a file",
        "description": "Returns the workspace's public URL when configured, otherwise a short-lived signed download URL. Resolves across storage lanes so a file uploaded before a storage switch still resolves.",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A usable URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url"
                  ],
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/visibility": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "patch": {
        "operationId": "setFileVisibility",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Set a file's visibility flag",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "visibility"
                ],
                "properties": {
                  "visibility": {
                    "type": "string",
                    "enum": [
                      "public",
                      "private"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated visibility.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "key",
                    "visibility"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "visibility": {
                      "type": "string",
                      "enum": [
                        "public",
                        "private"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/files/{key}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/FileKey"
        }
      ],
      "put": {
        "operationId": "putFile",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Upload a file",
        "description": "Send an Idempotency-Key to make retries safe for 24 hours. Reusing the key with the same effective request (keyed on the uploaded content) returns the original 201 response. Reusing it with a different request returns 409.",
        "parameters": [
          {
            "name": "replace",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Allow replacement. `X-Uploads-Replace: 1` is an equivalent header form."
          },
          {
            "name": "dryRun",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Validate and resolve the final key without writing."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dry-run result when `dryRun` is enabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDryRun"
                }
              }
            }
          },
          "201": {
            "description": "The file was stored.",
            "headers": {
              "Idempotency-Replayed": {
                "description": "Present with value `true` when the API replays a stored response.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FilePut"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "operationId": "getFile",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Read file metadata",
        "parameters": [
          {
            "name": "metadata",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Return only the queryable metadata map."
          }
        ],
        "responses": {
          "200": {
            "description": "Object metadata, or a metadata-only response when requested.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/FileHead"
                    },
                    {
                      "$ref": "#/components/schemas/MetadataResult"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "patchFileMetadata",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Merge file metadata",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The merged metadata map.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteFile",
        "security": [
          {
            "bearerAuth": [
              "files:delete"
            ]
          }
        ],
        "summary": "Delete a file",
        "responses": {
          "200": {
            "description": "The file was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/usage": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "getUsage",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Read workspace usage",
        "responses": {
          "200": {
            "description": "Usage counters, configured limits, credential scopes, and plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/usage/reconcile": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "post": {
        "operationId": "reconcileUsage",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Rebuild workspace usage counters",
        "tags": [
          "Maintenance"
        ],
        "description": "Potentially expensive: scans every object in the workspace's active storage lanes and rebuilds the usage ledger. Requires a bearer token with `files:write`; browser sessions are not accepted.",
        "x-uploads-potentially-expensive": true,
        "responses": {
          "200": {
            "description": "Reconciliation result and updated usage."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/usage/purge-expired": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "post": {
        "operationId": "purgeExpiredFiles",
        "security": [
          {
            "bearerAuth": [
              "files:delete"
            ]
          }
        ],
        "summary": "Purge files past the retention window",
        "tags": [
          "Maintenance"
        ],
        "description": "Destructive: permanently deletes objects older than the workspace's `retentionDays`, then reconciles usage. Requires a bearer token with `files:delete`; browser sessions are not accepted. The response is either `{ skipped: true }` or a purge and reconciliation result.",
        "x-uploads-destructive": true,
        "responses": {
          "200": {
            "description": "Purge result or a skipped result."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "post": {
        "operationId": "createGallery",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Create a gallery",
        "description": "Send an Idempotency-Key to make retries safe for 24 hours. Reusing the key with the same effective body returns the original 201 response. Reusing it with a different body returns 409.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GalleryCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The gallery was created.",
            "headers": {
              "Idempotency-Replayed": {
                "description": "Present with value `true` when the API replays a stored response.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Gallery"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "operationId": "listGalleries",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "List workspace galleries",
        "parameters": [
          {
            "$ref": "#/components/parameters/GalleryLimit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Enriched gallery summaries and an opaque continuation cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GalleryList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/by-reference": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "get": {
        "operationId": "findGalleriesByReference",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Find galleries by external reference",
        "parameters": [
          {
            "name": "provider",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "coordinate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/GalleryLimit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Gallery summaries and an opaque continuation cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GalleryList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/{galleryId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/GalleryId"
        }
      ],
      "get": {
        "operationId": "getGallery",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Read a gallery",
        "responses": {
          "200": {
            "description": "The gallery and its items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Gallery"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateGallery",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Update a gallery",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GalleryUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated gallery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Gallery"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteGallery",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Delete a gallery",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExpectedVersion"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The gallery was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/{galleryId}/items": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/GalleryId"
        }
      ],
      "post": {
        "operationId": "addGalleryItem",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Add a file to a gallery",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GalleryItemCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The file was already a member; the existing item is returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GalleryItem"
                }
              }
            }
          },
          "201": {
            "description": "The gallery item was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GalleryItem"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/{galleryId}/items/order": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/GalleryId"
        }
      ],
      "put": {
        "operationId": "reorderGalleryItems",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Replace the gallery item order",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GalleryOrder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ordered items and whether the order was unchanged."
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/{galleryId}/items/{itemId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/GalleryId"
        },
        {
          "name": "itemId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "removeGalleryItem",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Remove an item from a gallery",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExpectedVersion"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The gallery membership was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/{galleryId}/external-references": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/GalleryId"
        }
      ],
      "get": {
        "operationId": "listGalleryReferences",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "List gallery external references",
        "responses": {
          "200": {
            "description": "The gallery references."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "addGalleryReference",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Add an external reference",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GalleryReferenceCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The reference already existed and is returned unchanged."
          },
          "201": {
            "description": "The reference was created."
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/feeds": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        }
      ],
      "post": {
        "operationId": "createFeed",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Create a change feed",
        "description": "Creates a public newest-first screenshot feed for a GitHub owner/repo, optionally scoped to one pull request or issue. The same scope returns the existing feed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The existing feed for this scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          },
          "201": {
            "description": "The feed was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "operationId": "listFeeds",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "List workspace feeds",
        "parameters": [
          {
            "$ref": "#/components/parameters/GalleryLimit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of feed summaries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/feeds/{feedId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/FeedId"
        }
      ],
      "get": {
        "operationId": "getFeed",
        "security": [
          {
            "bearerAuth": [
              "files:read"
            ]
          }
        ],
        "summary": "Read one owned feed",
        "responses": {
          "200": {
            "description": "The feed and its current newest-first items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteFeed",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Soft-delete a feed",
        "responses": {
          "200": {
            "description": "The feed record was deleted. Uploaded objects stay.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{workspace}/galleries/{galleryId}/external-references/{referenceId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Workspace"
        },
        {
          "$ref": "#/components/parameters/GalleryId"
        },
        {
          "name": "referenceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "removeGalleryReference",
        "security": [
          {
            "bearerAuth": [
              "files:write"
            ]
          }
        ],
        "summary": "Remove an external reference",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExpectedVersion"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The external reference was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Workspace": {
        "name": "workspace",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "FileKey": {
        "name": "key",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Object key. It may include slashes."
      },
      "GalleryId": {
        "name": "galleryId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^gal_"
        }
      },
      "FeedId": {
        "name": "feedId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^feed_"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "A caller-scoped retry key retained for 24 hours. Use 1 to 255 visible ASCII characters.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        }
      },
      "Prefix": {
        "name": "prefix",
        "in": "query",
        "schema": {
          "type": "string"
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Opaque cursor returned by the previous page."
      },
      "FileLimit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000,
          "default": 100
        }
      },
      "GalleryLimit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      }
    },
    "responses": {
      "Validation": {
        "description": "Invalid request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid credential.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The credential lacks the required scope or role.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "NotFound": {
        "description": "The resource was not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Conflict": {
        "description": "The request conflicts with current resource state.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "The upload exceeds the workspace limit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "The bytes are not an allowed media type.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "RateLimited": {
        "description": "The workspace rate limit or upload budget was exceeded.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "type",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          }
        }
      },
      "Metadata": {
        "type": "object",
        "additionalProperties": {
          "type": "string"
        }
      },
      "MetadataResult": {
        "type": "object",
        "required": [
          "metadata"
        ],
        "properties": {
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        }
      },
      "MetadataPatch": {
        "type": "object",
        "properties": {
          "set": {
            "$ref": "#/components/schemas/Metadata"
          },
          "delete": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "FileHead": {
        "type": "object",
        "required": [
          "key",
          "size",
          "contentType",
          "url",
          "embedUrl"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "minimum": 0
          },
          "contentType": {
            "type": "string"
          },
          "uploaded": {
            "type": "string",
            "format": "date-time"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "embedUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "visibility": {
            "type": "string",
            "enum": [
              "public",
              "private"
            ]
          }
        }
      },
      "FileList": {
        "type": "object",
        "required": [
          "files",
          "cursor"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileHead"
            }
          },
          "prefixes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FileSearch": {
        "type": "object",
        "required": [
          "items",
          "truncated",
          "cursor"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileSearchItem"
            }
          },
          "truncated": {
            "type": "boolean"
          },
          "cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque continuation for the next page, or null on the last page."
          }
        }
      },
      "FileSearchItem": {
        "type": "object",
        "required": [
          "key",
          "url",
          "embedUrl",
          "metadata"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "embedUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FileByPath": {
        "type": "object",
        "required": [
          "groups",
          "catalog",
          "projects",
          "latest",
          "truncated",
          "catalogTruncated"
        ],
        "properties": {
          "groups": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "catalog": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "projects": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "latest": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "truncated": {
            "type": "boolean"
          },
          "catalogTruncated": {
            "type": "boolean"
          }
        }
      },
      "FileFacets": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "keys",
              "truncated"
            ],
            "properties": {
              "keys": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "truncated": {
                "type": "boolean"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "key",
              "values",
              "truncated"
            ],
            "properties": {
              "key": {
                "type": "string"
              },
              "values": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "truncated": {
                "type": "boolean"
              }
            }
          }
        ]
      },
      "SignRequest": {
        "type": "object",
        "required": [
          "key",
          "contentType"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "maxSize": {
            "type": "integer",
            "minimum": 1
          },
          "expiresIn": {
            "type": "integer",
            "minimum": 1,
            "maximum": 86400,
            "description": "Seconds until the signed URL expires. Capped at 900 for SVG and XML content types (issue #929)."
          },
          "replace": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "FilePut": {
        "allOf": [
          {
            "$ref": "#/components/schemas/FileHead"
          },
          {
            "type": "object",
            "required": [
              "workspace",
              "replaced"
            ],
            "properties": {
              "workspace": {
                "type": "string"
              },
              "replaced": {
                "type": "boolean"
              }
            }
          }
        ]
      },
      "FileDryRun": {
        "type": "object",
        "required": [
          "workspace",
          "key",
          "url",
          "embedUrl",
          "replaced",
          "wouldRefuse",
          "dryRun"
        ],
        "properties": {
          "workspace": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "embedUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "replaced": {
            "type": "boolean"
          },
          "wouldRefuse": {
            "type": "boolean"
          },
          "dryRun": {
            "const": true
          }
        }
      },
      "DeleteResult": {
        "type": "object",
        "required": [
          "deleted"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "deleted": {
            "const": true
          }
        },
        "anyOf": [
          {
            "required": [
              "id"
            ]
          },
          {
            "required": [
              "key"
            ]
          }
        ]
      },
      "Usage": {
        "type": "object",
        "required": [
          "workspace",
          "bytes",
          "objects",
          "uploadsInPeriod",
          "scopes",
          "plan"
        ],
        "properties": {
          "workspace": {
            "type": "string"
          },
          "bytes": {
            "type": "integer",
            "minimum": 0
          },
          "objects": {
            "type": "integer",
            "minimum": 0
          },
          "sharedBytes": {
            "type": "integer",
            "minimum": 0
          },
          "sharedObjects": {
            "type": "integer",
            "minimum": 0
          },
          "uploadsInPeriod": {
            "type": "integer",
            "minimum": 0
          },
          "periodStart": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "plan": {
            "type": "string"
          },
          "maxStorageBytes": {
            "type": "integer",
            "minimum": 0
          },
          "storageRemainingBytes": {
            "type": "integer",
            "minimum": 0
          },
          "maxUploadsPerPeriod": {
            "type": "integer",
            "minimum": 0
          },
          "uploadsRemaining": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ExpectedVersion": {
        "type": "object",
        "required": [
          "expectedVersion"
        ],
        "properties": {
          "expectedVersion": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "GallerySummary": {
        "type": "object",
        "required": [
          "id",
          "url",
          "workspace",
          "title",
          "visibility",
          "version"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^gal_"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "workspace": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "visibility": {
            "type": "string",
            "enum": [
              "public"
            ]
          },
          "coverItemId": {
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "itemCount": {
            "type": "integer",
            "minimum": 0
          },
          "references": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "previewUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "GalleryItem": {
        "type": "object",
        "required": [
          "id",
          "objectKey",
          "position",
          "caption",
          "altText",
          "createdAt",
          "status",
          "url",
          "embedUrl",
          "pageUrl",
          "contentType",
          "size",
          "uploaded",
          "modified"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "objectKey": {
            "type": "string"
          },
          "position": {
            "type": "integer",
            "minimum": 0
          },
          "caption": {
            "type": [
              "string",
              "null"
            ]
          },
          "altText": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "missing",
              "withheld"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "embedUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "pageUrl": {
            "type": "string",
            "format": "uri"
          },
          "contentType": {
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "uploaded": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "modified": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "posterUrl": {
            "type": "string",
            "format": "uri"
          },
          "videoDimensions": {
            "type": "object",
            "required": [
              "width",
              "height"
            ],
            "properties": {
              "width": {
                "type": "integer",
                "minimum": 1
              },
              "height": {
                "type": "integer",
                "minimum": 1
              }
            }
          }
        }
      },
      "Gallery": {
        "allOf": [
          {
            "$ref": "#/components/schemas/GallerySummary"
          },
          {
            "type": "object",
            "required": [
              "items"
            ],
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/GalleryItem"
                }
              }
            }
          }
        ]
      },
      "GalleryList": {
        "type": "object",
        "required": [
          "galleries",
          "nextCursor"
        ],
        "properties": {
          "galleries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GallerySummary"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FeedCreate": {
        "type": "object",
        "required": [
          "repo"
        ],
        "properties": {
          "repo": {
            "type": "string",
            "description": "GitHub owner/repo."
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional exact page-path metadata filter."
          },
          "number": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "description": "Optional pull request or issue number. Filters on gh.number."
          },
          "kind": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "pull",
              "issue"
            ],
            "description": "Display-only. Set automatically when you pass pr or issue."
          },
          "pr": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "description": "Alias for number with kind=pull. Mutually exclusive with number and issue."
          },
          "issue": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "description": "Alias for number with kind=issue. Mutually exclusive with number and pr."
          }
        }
      },
      "FeedSummary": {
        "type": "object",
        "required": [
          "id",
          "url",
          "workspace",
          "repo",
          "title",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^feed_"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical public page (`/c/<id>`)."
          },
          "workspace": {
            "type": "string"
          },
          "repo": {
            "type": "string"
          },
          "path": {
            "type": [
              "string",
              "null"
            ]
          },
          "number": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "kind": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "pull",
              "issue"
            ]
          },
          "title": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FeedItem": {
        "type": "object",
        "required": [
          "id",
          "filename",
          "status",
          "url",
          "embedUrl"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "objectKey": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "missing",
              "withheld"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "embedUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "pageUrl": {
            "type": "string",
            "format": "uri"
          },
          "contentType": {
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "uploaded": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "modified": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "path": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Feed": {
        "allOf": [
          {
            "$ref": "#/components/schemas/FeedSummary"
          },
          {
            "type": "object",
            "required": [
              "items"
            ],
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/FeedItem"
                }
              }
            }
          }
        ]
      },
      "FeedList": {
        "type": "object",
        "required": [
          "feeds",
          "nextCursor"
        ],
        "properties": {
          "feeds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeedSummary"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "GalleryCreate": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          }
        }
      },
      "GalleryUpdate": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExpectedVersion"
          },
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ],
                "maxLength": 2000
              },
              "coverItemId": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "GalleryItemCreate": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExpectedVersion"
          },
          {
            "type": "object",
            "required": [
              "objectKey"
            ],
            "properties": {
              "objectKey": {
                "type": "string"
              },
              "caption": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "altText": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "GalleryOrder": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExpectedVersion"
          },
          {
            "type": "object",
            "required": [
              "itemIds"
            ],
            "properties": {
              "itemIds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        ]
      },
      "GalleryReferenceCreate": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExpectedVersion"
          },
          {
            "type": "object",
            "required": [
              "provider",
              "coordinate"
            ],
            "properties": {
              "provider": {
                "type": "string"
              },
              "coordinate": {
                "type": "string"
              }
            }
          }
        ]
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Workspace token from `uploads login` or `/account/developers`. Canonical routes can also accept an uploads.sh browser session, but public API integrations should use a workspace token. Tokens carry named scopes `files:read`, `files:write`, and `files:delete`; each operation lists the required scope as a role name on this scheme. REST v1 does not accept OAuth access tokens (those are for the hosted MCP). Scope catalog: https://api.uploads.sh/.well-known/oauth-protected-resource"
      },
      "oauth2": {
        "type": "oauth2",
        "description": "Named permission scopes for workspace tokens (this API) and for OAuth 2.1 access tokens on the hosted MCP at https://agents.uploads.sh/mcp. REST v1 authenticates with `bearerAuth` only. Request the scopes listed on each operation. Discovery: https://uploads.sh/.well-known/oauth-authorization-server and https://api.uploads.sh/.well-known/oauth-protected-resource",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://uploads.sh/api/auth/oauth2/authorize",
            "tokenUrl": "https://auth.uploads.sh/api/auth/oauth2/token",
            "scopes": {
              "files:read": "List, search, read metadata, usage, galleries, and feeds.",
              "files:write": "Upload, update metadata, galleries, feeds, and usage reconcile.",
              "files:delete": "Delete stored objects and purge expired objects."
            }
          }
        }
      }
    }
  }
}
