{
  "openapi": "3.1.0",
  "info": {
    "title": "Graphon storage API",
    "version": "0.1.0",
    "description": "JSON API for buckets and objects on the G4 storage host. Authenticate with a bearer API key or temporary key. Object bytes move through presigned S3 requests, or through any S3 tool with the same API key."
  },
  "paths": {
    "/v1/workspaces/{workspaceId}/buckets": {
      "get": {
        "tags": ["Buckets"],
        "operationId": "list_buckets",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Return only the bucket with this exact name."
            },
            "required": false,
            "description": "Return only the bucket with this exact name."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of buckets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BucketList"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Lists the buckets in the workspace. Pass name to find one bucket by its exact name. Role: viewer or higher.",
        "summary": "List buckets",
        "x-cli-example": "graphon buckets list"
      },
      "post": {
        "tags": ["Buckets"],
        "operationId": "create_bucket",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BucketEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          },
          "503": {
            "description": "The storage provider is busy or failed. Try again soon.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The storage provider is busy or failed. Try again soon."
                }
              }
            }
          }
        },
        "description": "Creates a bucket and returns it when it is active. Search is enabled unless you send search disabled, and it cannot change later. Role: editor or higher.",
        "summary": "Create a bucket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBucketRequest"
              }
            }
          },
          "required": true
        },
        "x-cli-example": "graphon buckets create support-tickets --provider gcp --location us-central1"
      }
    },
    "/v1/workspaces/{workspaceId}/bucket-name-availability": {
      "get": {
        "tags": ["Buckets"],
        "operationId": "check_bucket_name",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The bucket name to check.",
              "examples": ["support-tickets"]
            },
            "required": true,
            "description": "The bucket name to check."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Whether a bucket name is free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NameAvailability"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Returns whether a bucket name is valid and free. Bucket names are unique across all workspaces. Role: viewer or higher.",
        "summary": "Check a bucket name",
        "x-cli-example": "graphon buckets availability --name support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}": {
      "get": {
        "tags": ["Buckets"],
        "operationId": "get_bucket",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One bucket, with its usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BucketDetails"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Returns one bucket with its settings and usage. Role: viewer or higher.",
        "summary": "Get a bucket",
        "x-cli-example": "graphon buckets get support-tickets"
      },
      "patch": {
        "tags": ["Buckets"],
        "operationId": "update_bucket",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Bucket"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Changes the permission, availability, or policy of a bucket. A missing field keeps its value. Role: editor or higher.",
        "summary": "Update a bucket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBucketRequest"
              }
            }
          },
          "required": true
        },
        "x-cli-example": "graphon buckets update support-tickets --permission public-read"
      },
      "delete": {
        "tags": ["Buckets"],
        "operationId": "delete_bucket",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "confirmName",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The exact current bucket name.",
              "examples": ["support-tickets"]
            },
            "required": true,
            "description": "The exact current bucket name."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "Success"
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Deletes an empty bucket. Send the exact bucket name as confirmName. The bucket stays restorable for seven days. Role: editor or higher.",
        "summary": "Delete a bucket",
        "x-cli-example": "graphon buckets delete support-tickets --confirm-name support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/retry-provisioning": {
      "post": {
        "tags": ["Buckets"],
        "operationId": "retry_bucket_provisioning",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BucketEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          },
          "503": {
            "description": "The storage provider is busy or failed. Try again soon.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The storage provider is busy or failed. Try again soon."
                }
              }
            }
          }
        },
        "description": "Provisions a bucket again after it failed, and returns it when it is active. Role: editor or higher.",
        "summary": "Retry bucket provisioning",
        "x-cli-example": "graphon buckets retry support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/empty": {
      "post": {
        "tags": ["Buckets"],
        "operationId": "empty_bucket",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "The bucket and the job that empties it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["bucket", "job"],
                  "properties": {
                    "bucket": {
                      "$ref": "#/components/schemas/Bucket"
                    },
                    "job": {
                      "type": "object",
                      "required": ["id", "status"],
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The job id."
                        },
                        "status": {
                          "type": "string",
                          "description": "pending until the empty finishes."
                        }
                      },
                      "additionalProperties": false
                    }
                  },
                  "additionalProperties": false,
                  "description": "The bucket and the job that empties it.",
                  "title": "EmptyBucketAccepted"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Deletes every object in the bucket. Send the exact bucket name as confirmName. Objects under retention stay, and the call returns object_locked with their keys. Role: editor or higher.",
        "summary": "Empty a bucket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmNameRequest"
              }
            }
          },
          "required": true
        },
        "x-cli-example": "graphon buckets empty support-tickets --confirm-name support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/restore": {
      "post": {
        "tags": ["Buckets"],
        "operationId": "restore_bucket",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "The bucket and the job that changes it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["bucket", "job"],
                  "properties": {
                    "bucket": {
                      "$ref": "#/components/schemas/Bucket"
                    },
                    "job": {
                      "$ref": "#/components/schemas/Job"
                    }
                  },
                  "additionalProperties": false,
                  "description": "The bucket and the job that changes it.",
                  "title": "BucketJob"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Restores a deleted bucket within its recovery window. Role: editor or higher.",
        "summary": "Restore a bucket",
        "x-cli-example": "graphon buckets restore support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/jobs/{jobId}": {
      "get": {
        "tags": ["Buckets"],
        "operationId": "get_job",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "jobId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The job id.",
              "examples": ["job_4b1d0c"]
            },
            "required": true,
            "description": "The job id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Background work for a bucket or an object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Returns the status of background work, such as an empty or a copy. Role: viewer or higher.",
        "summary": "Get a job",
        "x-cli-example": "graphon jobs get job_4b1d0c"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/objects": {
      "get": {
        "tags": ["Objects"],
        "operationId": "list_objects",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "prefix",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Return only keys that start with this text."
            },
            "required": false,
            "description": "Return only keys that start with this text."
          },
          {
            "name": "delimiter",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Group keys into prefixes at this character, usually \"/\"."
            },
            "required": false,
            "description": "Group keys into prefixes at this character, usually \"/\"."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The nextCursor from the previous page."
            },
            "required": false,
            "description": "The nextCursor from the previous page."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The most keys to read for one page, from 1 to 1000. The default is 1000.",
              "pattern": "^[1-9][0-9]{0,3}$"
            },
            "required": false,
            "description": "The most keys to read for one page, from 1 to 1000. The default is 1000."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One page of objects.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectPage"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Lists live objects in key order, one page at a time. Pass delimiter \"/\" to group keys into prefixes. Role: viewer or higher.",
        "summary": "List objects",
        "x-cli-example": "graphon objects list support-tickets --prefix incidents/"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/objects/{keyToken}": {
      "get": {
        "tags": ["Objects"],
        "operationId": "get_object_metadata",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "keyToken",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The object key, base64url-encoded without padding.",
              "examples": ["aW5jaWRlbnRzL2NoZWNrb3V0LXRpbWVvdXQuanNvbg"]
            },
            "required": true,
            "description": "The object key, base64url-encoded without padding."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One object version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectSummary"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Returns the metadata of the live version of one object, without its bytes. Role: viewer or higher.",
        "summary": "Get object metadata",
        "x-cli-example": "graphon objects stat support-tickets incidents/checkout-timeout.json"
      },
      "delete": {
        "tags": ["Objects"],
        "operationId": "delete_object",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "keyToken",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The object key, base64url-encoded without padding.",
              "examples": ["aW5jaWRlbnRzL2NoZWNrb3V0LXRpbWVvdXQuanNvbg"]
            },
            "required": true,
            "description": "The object key, base64url-encoded without padding."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "What a delete removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteObjectResult"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Deletes one object. The deleted version stays recoverable for the bucket recovery window. Role: editor or higher.",
        "summary": "Delete an object",
        "x-cli-example": "graphon objects delete support-tickets incidents/checkout-timeout.json"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/objects/{keyToken}/versions": {
      "get": {
        "tags": ["Objects"],
        "operationId": "list_object_versions",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "keyToken",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The object key, base64url-encoded without padding.",
              "examples": ["aW5jaWRlbnRzL2NoZWNrb3V0LXRpbWVvdXQuanNvbg"]
            },
            "required": true,
            "description": "The object key, base64url-encoded without padding."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The versions of one object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionList"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Lists the live versions and delete markers of one object, newest first. Role: viewer or higher.",
        "summary": "List object versions",
        "x-cli-example": "graphon objects versions support-tickets incidents/checkout-timeout.json"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/objects/{keyToken}/restore": {
      "post": {
        "tags": ["Objects"],
        "operationId": "restore_object",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "keyToken",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The object key, base64url-encoded without padding.",
              "examples": ["aW5jaWRlbnRzL2NoZWNrb3V0LXRpbWVvdXQuanNvbg"]
            },
            "required": true,
            "description": "The object key, base64url-encoded without padding."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "The job that does the work.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["job"],
                  "properties": {
                    "job": {
                      "$ref": "#/components/schemas/Job"
                    }
                  },
                  "additionalProperties": false,
                  "description": "The job that does the work.",
                  "title": "JobEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Restores a deleted or replaced version from recovery. Get the recoveryId from GET …/recovery. Role: editor or higher.",
        "summary": "Restore an object",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestoreObjectRequest"
              }
            }
          },
          "required": true
        },
        "x-cli-example": "graphon objects restore support-tickets incidents/checkout-timeout.json --recovery-id <recoveryId>"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/objects/{keyToken}/copy": {
      "post": {
        "tags": ["Objects"],
        "operationId": "copy_object",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          },
          {
            "name": "keyToken",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The object key, base64url-encoded without padding.",
              "examples": ["aW5jaWRlbnRzL2NoZWNrb3V0LXRpbWVvdXQuanNvbg"]
            },
            "required": true,
            "description": "The object key, base64url-encoded without padding."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "The job that does the work.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["job"],
                  "properties": {
                    "job": {
                      "$ref": "#/components/schemas/Job"
                    }
                  },
                  "additionalProperties": false,
                  "description": "The job that does the work.",
                  "title": "JobEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          },
          "503": {
            "description": "The storage provider is busy or failed. Try again soon.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The storage provider is busy or failed. Try again soon."
                }
              }
            }
          }
        },
        "description": "Copies an object to another key in the same bucket. Role: editor or higher.",
        "summary": "Copy an object",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CopyObjectRequest"
              }
            }
          },
          "required": true
        },
        "x-cli-example": "graphon objects copy support-tickets a.json --destination-key b.json"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/presign": {
      "post": {
        "tags": ["Objects"],
        "operationId": "presign_object_request",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One presigned S3 request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresignResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          },
          "413": {
            "description": "One request cannot carry this many bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "One request cannot carry this many bytes."
                }
              }
            }
          }
        },
        "description": "Returns one presigned S3 request for one object key. Send it before expiresAt, with the returned headers exactly. Operations other than GetObject need the editor role. Role: viewer or higher.",
        "summary": "Presign an S3 request",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PresignRequest"
              }
            }
          },
          "required": true
        },
        "x-cli-example": "graphon objects put support-tickets incidents/checkout-timeout.json --file ./checkout-timeout.json"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/usage": {
      "get": {
        "tags": ["Insights"],
        "operationId": "get_bucket_usage",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Storage used by one bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Returns the bytes and objects that one bucket stores. Role: viewer or higher.",
        "summary": "Get bucket usage",
        "x-cli-example": "graphon buckets usage support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/recovery": {
      "get": {
        "tags": ["Insights"],
        "operationId": "list_bucket_recovery",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Recovery copies in one bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecoveryList"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Lists deleted or replaced versions that can still be restored. Role: viewer or higher.",
        "summary": "List bucket recovery",
        "x-cli-example": "graphon buckets recovery support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/activity": {
      "get": {
        "tags": ["Insights"],
        "operationId": "list_bucket_activity",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Recent activity in one bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivityList"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Lists recent changes in one bucket, newest first. Role: viewer or higher.",
        "summary": "List bucket activity",
        "x-cli-example": "graphon buckets activity support-tickets"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/metrics": {
      "get": {
        "tags": ["Insights"],
        "operationId": "get_bucket_metrics",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Storage used by one bucket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "400": {
            "description": "The request body, query, or path is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The request body, query, or path is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer key is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bearer key is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid, but its role or workspace does not allow the action.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The key is valid, but its role or workspace does not allow the action."
                }
              }
            }
          },
          "404": {
            "description": "The bucket, object, or job does not exist, or this key cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The bucket, object, or job does not exist, or this key cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the bucket state, such as a bucket that is not active yet.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StorageError"
                    }
                  ],
                  "description": "The change conflicts with the bucket state, such as a bucket that is not active yet."
                }
              }
            }
          }
        },
        "description": "Returns storage metrics for one bucket. Role: viewer or higher.",
        "summary": "Get bucket metrics",
        "x-cli-example": "graphon buckets metrics support-tickets"
      }
    }
  },
  "components": {
    "schemas": {
      "BucketList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Bucket"
            },
            "description": "The buckets."
          }
        },
        "additionalProperties": false,
        "description": "A list of buckets.",
        "title": "BucketList",
        "examples": [
          {
            "items": [
              {
                "id": "bktA1b2C3d4E5",
                "workspaceId": "wspQ7WsH2Np5L",
                "name": "support-tickets",
                "provider": "gcp",
                "location": "us-central1",
                "storageClass": "standard",
                "permission": "private",
                "phase": "active",
                "availability": "online",
                "search": "enabled",
                "objectCount": 12,
                "revision": 1,
                "createdAt": "2026-10-01T12:00:00.000Z",
                "policy": {}
              }
            ]
          }
        ]
      },
      "Bucket": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "provider",
          "location",
          "storageClass",
          "permission",
          "phase",
          "availability",
          "search",
          "objectCount",
          "revision",
          "createdAt",
          "policy"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The bucket id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "The bucket name. S3 tools use it."
          },
          "provider": {
            "type": "string",
            "description": "The storage provider: gcp or r2."
          },
          "location": {
            "type": "string",
            "description": "The provider region."
          },
          "storageClass": {
            "type": "string",
            "description": "The storage class."
          },
          "permission": {
            "type": "string",
            "enum": ["private", "public-read"],
            "description": "Who can read objects: private, or public-read for anonymous GET and HEAD."
          },
          "phase": {
            "type": "string",
            "description": "provisioning, active, failed, or deleted. Most routes need active."
          },
          "availability": {
            "type": "string",
            "enum": ["online", "offline"],
            "description": "An offline bucket rejects reads and writes."
          },
          "search": {
            "type": "string",
            "enum": ["enabled", "disabled"],
            "description": "Whether Graphon indexes the objects for search. Fixed when the bucket is created."
          },
          "objectCount": {
            "type": "number",
            "description": "The number of live objects."
          },
          "revision": {
            "type": "number",
            "description": "The bucket revision."
          },
          "createdAt": {
            "type": "string",
            "description": "When the bucket was created, in UTC."
          },
          "policy": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "$id": "/schemas/unknown",
              "title": "unknown"
            },
            "description": "Bucket policy settings, such as versioning and retention."
          }
        },
        "additionalProperties": false,
        "description": "One bucket.",
        "title": "Bucket",
        "examples": [
          {
            "id": "bktA1b2C3d4E5",
            "workspaceId": "wspQ7WsH2Np5L",
            "name": "support-tickets",
            "provider": "gcp",
            "location": "us-central1",
            "storageClass": "standard",
            "permission": "private",
            "phase": "active",
            "availability": "online",
            "search": "enabled",
            "objectCount": 12,
            "revision": 1,
            "createdAt": "2026-10-01T12:00:00.000Z",
            "policy": {}
          }
        ]
      },
      "StorageError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable error token, such as not_found or bucket_not_ready."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation."
              },
              "retained": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": ["key", "retainUntil"],
                  "properties": {
                    "key": {
                      "type": "string",
                      "description": "The object key."
                    },
                    "retainUntil": {
                      "type": "string",
                      "description": "When the retention ends, in UTC."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "For object_locked: the objects that retention kept."
              }
            },
            "additionalProperties": false,
            "description": "Machine-readable failure."
          }
        },
        "additionalProperties": false,
        "description": "Error body returned by the storage API.",
        "title": "StorageError"
      },
      "NameAvailability": {
        "type": "object",
        "required": ["available", "reason"],
        "properties": {
          "available": {
            "type": "boolean",
            "description": "Whether the name can be used."
          },
          "reason": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["invalid", "unavailable"]
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the name cannot be used, or null."
          }
        },
        "additionalProperties": false,
        "description": "Whether a bucket name is free.",
        "title": "NameAvailability",
        "examples": [
          {
            "available": true,
            "reason": null
          }
        ]
      },
      "CreateBucketRequest": {
        "type": "object",
        "required": ["name", "provider", "location"],
        "properties": {
          "name": {
            "type": "string",
            "description": "3 to 63 lowercase letters, digits, and hyphens.",
            "examples": ["support-tickets"]
          },
          "provider": {
            "type": "string",
            "description": "gcp or r2.",
            "examples": ["gcp"]
          },
          "location": {
            "type": "string",
            "description": "The provider region, for example us-central1.",
            "examples": ["us-central1"]
          },
          "search": {
            "type": "string",
            "enum": ["enabled", "disabled"],
            "description": "Whether Graphon indexes the objects for search. Fixed when the bucket is created."
          },
          "storageClass": {
            "type": "string",
            "description": "The storage class. The default is standard."
          },
          "permission": {
            "type": "string",
            "enum": ["private", "public-read"],
            "description": "Who can read objects: private, or public-read for anonymous GET and HEAD."
          },
          "policy": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "$id": "/schemas/unknown",
              "title": "unknown"
            },
            "description": "Bucket policy settings, such as versioning and retention."
          }
        },
        "additionalProperties": false,
        "description": "A new bucket.",
        "title": "CreateBucketRequest",
        "examples": [
          {
            "name": "support-tickets",
            "provider": "gcp",
            "location": "us-central1",
            "search": "enabled"
          }
        ]
      },
      "BucketEnvelope": {
        "type": "object",
        "required": ["bucket"],
        "properties": {
          "bucket": {
            "$ref": "#/components/schemas/Bucket"
          }
        },
        "additionalProperties": false,
        "description": "One bucket.",
        "title": "BucketEnvelope"
      },
      "BucketDetails": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "provider",
          "location",
          "storageClass",
          "permission",
          "phase",
          "availability",
          "search",
          "objectCount",
          "revision",
          "createdAt",
          "policy",
          "usage"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The bucket id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "The bucket name. S3 tools use it."
          },
          "provider": {
            "type": "string",
            "description": "The storage provider: gcp or r2."
          },
          "location": {
            "type": "string",
            "description": "The provider region."
          },
          "storageClass": {
            "type": "string",
            "description": "The storage class."
          },
          "permission": {
            "type": "string",
            "enum": ["private", "public-read"],
            "description": "Who can read objects: private, or public-read for anonymous GET and HEAD."
          },
          "phase": {
            "type": "string",
            "description": "provisioning, active, failed, or deleted. Most routes need active."
          },
          "availability": {
            "type": "string",
            "enum": ["online", "offline"],
            "description": "An offline bucket rejects reads and writes."
          },
          "search": {
            "type": "string",
            "enum": ["enabled", "disabled"],
            "description": "Whether Graphon indexes the objects for search. Fixed when the bucket is created."
          },
          "objectCount": {
            "type": "number",
            "description": "The number of live objects."
          },
          "revision": {
            "type": "number",
            "description": "The bucket revision."
          },
          "createdAt": {
            "type": "string",
            "description": "When the bucket was created, in UTC."
          },
          "policy": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "$id": "/schemas/unknown",
              "title": "unknown"
            },
            "description": "Bucket policy settings, such as versioning and retention."
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          }
        },
        "additionalProperties": false,
        "description": "One bucket, with its usage.",
        "title": "BucketDetails"
      },
      "Usage": {
        "type": "object",
        "required": ["liveBytes", "recoveryBytes", "objectCount"],
        "properties": {
          "liveBytes": {
            "type": "string",
            "description": "Bytes in live versions, as a decimal string."
          },
          "recoveryBytes": {
            "type": "string",
            "description": "Bytes kept for recovery, as a decimal string."
          },
          "objectCount": {
            "type": "number",
            "description": "The number of live objects."
          }
        },
        "additionalProperties": false,
        "description": "Storage used by one bucket.",
        "title": "Usage",
        "examples": [
          {
            "liveBytes": "2048",
            "recoveryBytes": "0",
            "objectCount": 12
          }
        ]
      },
      "UpdateBucketRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "permission": {
            "type": "string",
            "enum": ["private", "public-read"],
            "description": "Who can read objects: private, or public-read for anonymous GET and HEAD."
          },
          "availability": {
            "type": "string",
            "enum": ["online", "offline"],
            "description": "An offline bucket rejects reads and writes."
          },
          "policy": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "$id": "/schemas/unknown",
              "title": "unknown"
            },
            "description": "Bucket policy settings, such as versioning and retention."
          }
        },
        "additionalProperties": false,
        "description": "Bucket settings to change. A missing field keeps its value.",
        "title": "UpdateBucketRequest",
        "examples": [
          {
            "permission": "public-read"
          }
        ]
      },
      "ConfirmNameRequest": {
        "type": "object",
        "required": ["confirmName"],
        "properties": {
          "confirmName": {
            "type": "string",
            "description": "The exact current bucket name.",
            "examples": ["support-tickets"]
          }
        },
        "additionalProperties": false,
        "description": "Confirms a destructive change by naming the bucket.",
        "title": "ConfirmNameRequest",
        "examples": [
          {
            "confirmName": "support-tickets"
          }
        ]
      },
      "Job": {
        "type": "object",
        "required": ["id", "kind", "status", "createdAt", "updatedAt"],
        "properties": {
          "id": {
            "type": "string",
            "description": "The job id."
          },
          "kind": {
            "type": "string",
            "description": "What the job does."
          },
          "status": {
            "type": "string",
            "description": "pending, running, succeeded, or failed."
          },
          "createdAt": {
            "type": "string",
            "description": "When the job was created, in UTC."
          },
          "updatedAt": {
            "type": "string",
            "description": "When the job last changed, in UTC."
          }
        },
        "additionalProperties": false,
        "description": "Background work for a bucket or an object.",
        "title": "Job"
      },
      "ObjectPage": {
        "type": "object",
        "required": ["items", "nextCursor"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/ObjectSummary"
                },
                {
                  "$ref": "#/components/schemas/CommonPrefix"
                }
              ]
            },
            "description": "Objects in key order, then the prefixes."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as cursor to read the next page, or null on the last page. A page can hold fewer items than limit, even none, before the last page."
          }
        },
        "additionalProperties": false,
        "description": "One page of objects.",
        "title": "ObjectPage"
      },
      "ObjectSummary": {
        "type": "object",
        "required": [
          "kind",
          "id",
          "bucketId",
          "key",
          "versionId",
          "sizeBytes",
          "contentType",
          "etag",
          "createdAt",
          "revision",
          "retainUntil",
          "checksums"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": ["object"]
          },
          "id": {
            "type": "string",
            "description": "The version id."
          },
          "bucketId": {
            "type": "string",
            "description": "The bucket id."
          },
          "key": {
            "type": "string",
            "description": "The object key."
          },
          "versionId": {
            "type": "string",
            "description": "The version id."
          },
          "sizeBytes": {
            "type": "string",
            "description": "The size in bytes, as a decimal string."
          },
          "contentType": {
            "type": "string",
            "description": "The content type."
          },
          "etag": {
            "type": "string",
            "description": "The entity tag."
          },
          "createdAt": {
            "type": "string",
            "description": "When the version was written, in UTC."
          },
          "revision": {
            "type": "number",
            "description": "The metadata revision."
          },
          "retainUntil": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When retention ends, in UTC, or null."
          },
          "checksums": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "type": "string"
            },
            "description": "Stored checksums by algorithm."
          }
        },
        "additionalProperties": false,
        "description": "One object version.",
        "title": "ObjectSummary"
      },
      "CommonPrefix": {
        "type": "object",
        "required": ["kind", "prefix"],
        "properties": {
          "kind": {
            "type": "string",
            "enum": ["prefix"]
          },
          "prefix": {
            "type": "string",
            "description": "A key prefix that groups more objects."
          }
        },
        "additionalProperties": false,
        "description": "A group of keys under one prefix.",
        "title": "CommonPrefix"
      },
      "VersionList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ObjectSummary"
            },
            "description": "Versions, newest first."
          }
        },
        "additionalProperties": false,
        "description": "The versions of one object.",
        "title": "VersionList"
      },
      "DeleteObjectResult": {
        "type": "object",
        "required": ["removedVersionId", "deleteMarkerVersionId", "cleanupPending"],
        "properties": {
          "removedVersionId": {
            "type": "string",
            "description": "The version that was removed."
          },
          "deleteMarkerVersionId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The delete marker in a versioned bucket, or null."
          },
          "cleanupPending": {
            "type": "boolean",
            "description": "Provider cleanup is still running."
          }
        },
        "additionalProperties": false,
        "description": "What a delete removed.",
        "title": "DeleteObjectResult"
      },
      "RestoreObjectRequest": {
        "type": "object",
        "required": ["recoveryId"],
        "properties": {
          "recoveryId": {
            "type": "string",
            "description": "The recoveryId from GET …/recovery."
          }
        },
        "additionalProperties": false,
        "description": "The recovery copy to restore.",
        "title": "RestoreObjectRequest",
        "examples": [
          {
            "recoveryId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f"
          }
        ]
      },
      "CopyObjectRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "destinationKey": {
            "type": "string",
            "description": "The key to copy to, in the same bucket."
          }
        },
        "additionalProperties": false,
        "description": "Where to copy the object.",
        "title": "CopyObjectRequest",
        "examples": [
          {
            "destinationKey": "incidents/checkout-timeout-copy.json"
          }
        ]
      },
      "PresignRequest": {
        "anyOf": [
          {
            "type": "object",
            "required": ["operation", "key", "contentType", "lengthBytes"],
            "properties": {
              "operation": {
                "type": "string",
                "enum": ["PutObject"]
              },
              "key": {
                "type": "string",
                "description": "The object key."
              },
              "contentType": {
                "type": "string",
                "description": "The object content type."
              },
              "lengthBytes": {
                "type": "string",
                "description": "The body size in bytes, as a string of digits. It is signed.",
                "pattern": "^\\d{1,16}$"
              },
              "sha256": {
                "type": "string",
                "description": "The base64 SHA-256 of the body. G4 signs it and rejects other bytes.",
                "pattern": "^[A-Za-z0-9+/]{43}=$"
              },
              "ifNoneMatch": {
                "type": "string",
                "enum": ["*"],
                "description": "Send * to create only. G4 rejects the PUT if the key exists."
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": ["operation", "key"],
            "properties": {
              "operation": {
                "type": "string",
                "enum": ["GetObject"]
              },
              "key": {
                "type": "string",
                "description": "The object key."
              },
              "versionId": {
                "type": "string",
                "description": "The version to read."
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": ["operation", "key", "contentType"],
            "properties": {
              "operation": {
                "type": "string",
                "enum": ["CreateMultipartUpload"]
              },
              "key": {
                "type": "string",
                "description": "The object key."
              },
              "contentType": {
                "type": "string",
                "description": "The object content type."
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": ["operation", "key", "uploadId", "partNumber", "lengthBytes"],
            "properties": {
              "operation": {
                "type": "string",
                "enum": ["UploadPart"]
              },
              "key": {
                "type": "string",
                "description": "The object key."
              },
              "uploadId": {
                "type": "string",
                "description": "The multipart upload id."
              },
              "partNumber": {
                "type": "integer",
                "description": "The part number, from 1 to 10000.",
                "title": "between(1, 10000)",
                "minimum": 1,
                "maximum": 10000
              },
              "lengthBytes": {
                "type": "string",
                "description": "The body size in bytes, as a string of digits. It is signed.",
                "pattern": "^\\d{1,16}$"
              },
              "sha256": {
                "type": "string",
                "description": "The base64 SHA-256 of the body. G4 signs it and rejects other bytes.",
                "pattern": "^[A-Za-z0-9+/]{43}=$"
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": ["operation", "key", "uploadId"],
            "properties": {
              "operation": {
                "type": "string",
                "enum": ["CompleteMultipartUpload"]
              },
              "key": {
                "type": "string",
                "description": "The object key."
              },
              "uploadId": {
                "type": "string",
                "description": "The multipart upload id."
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": ["operation", "key", "uploadId"],
            "properties": {
              "operation": {
                "type": "string",
                "enum": ["AbortMultipartUpload"]
              },
              "key": {
                "type": "string",
                "description": "The object key."
              },
              "uploadId": {
                "type": "string",
                "description": "The multipart upload id."
              }
            },
            "additionalProperties": false
          }
        ],
        "description": "One S3 request to presign.",
        "title": "PresignRequest",
        "examples": [
          {
            "operation": "PutObject",
            "key": "incidents/checkout-timeout.json",
            "contentType": "application/json",
            "lengthBytes": "2048"
          }
        ]
      },
      "PresignResponse": {
        "type": "object",
        "required": ["method", "url", "headers", "expiresAt"],
        "properties": {
          "method": {
            "type": "string",
            "enum": ["PUT", "GET", "POST", "DELETE"],
            "description": "The HTTP method to send."
          },
          "url": {
            "type": "string",
            "description": "The presigned URL on the G4 host."
          },
          "headers": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "type": "string"
            },
            "description": "Send these headers exactly. G4 signs them."
          },
          "expiresAt": {
            "type": "string",
            "description": "When the URL stops working, in UTC."
          }
        },
        "additionalProperties": false,
        "description": "One presigned S3 request.",
        "title": "PresignResponse"
      },
      "RecoveryList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["recoveryId", "key", "versionId", "expiresAt", "sizeBytes"],
              "properties": {
                "recoveryId": {
                  "type": "string",
                  "description": "Pass to POST …/restore."
                },
                "key": {
                  "type": "string",
                  "description": "The object key."
                },
                "versionId": {
                  "type": "string",
                  "description": "The version id."
                },
                "expiresAt": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When recovery ends, in UTC, or null when it has no end."
                },
                "sizeBytes": {
                  "type": "string",
                  "description": "The size in bytes."
                }
              },
              "additionalProperties": false
            },
            "description": "Deleted or replaced versions that can be restored."
          }
        },
        "additionalProperties": false,
        "description": "Recovery copies in one bucket.",
        "title": "RecoveryList"
      },
      "ActivityList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["id", "kind", "outcome", "at", "detail"],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "The activity id."
                },
                "kind": {
                  "type": "string",
                  "description": "What happened."
                },
                "outcome": {
                  "type": "string",
                  "description": "succeeded or failed."
                },
                "at": {
                  "type": "string",
                  "description": "When it happened, in UTC."
                },
                "detail": {
                  "$id": "/schemas/unknown",
                  "description": "Details for the kind.",
                  "title": "unknown"
                }
              },
              "additionalProperties": false
            },
            "description": "The newest activity first."
          }
        },
        "additionalProperties": false,
        "description": "Recent activity in one bucket.",
        "title": "ActivityList"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "Send Authorization: Bearer with an API key (gak_…) or a temporary key (gtk_…). A key acts only in its own workspace, at its role: viewer, editor, or admin.",
        "type": "http",
        "scheme": "bearer"
      }
    }
  },
  "tags": [
    {
      "name": "Buckets",
      "description": "Buckets and their settings."
    },
    {
      "name": "Objects",
      "description": "Objects, their versions, and presigned S3 requests."
    },
    {
      "name": "Insights",
      "description": "Usage, activity, metrics, and recovery for a bucket."
    }
  ],
  "servers": [
    {
      "url": "https://g4.beta.graphon.ai"
    }
  ]
}
