{
  "openapi": "3.1.0",
  "info": {
    "title": "Graphon API",
    "version": "0.2.0",
    "description": "Public machine API for Graphon workspaces. Authenticate with a bearer API key or an OAuth access token for this API. Management paths are under /v1/workspaces/{workspaceId}. This document omits marketing /www routes, the OAuth endpoints under /oauth and /.well-known, and health probes."
  },
  "paths": {
    "/v1/me": {
      "get": {
        "tags": ["Account"],
        "operationId": "get_me",
        "parameters": [],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "required": ["kind", "userId", "email", "name"],
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": ["user"]
                        },
                        "userId": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "required": ["kind", "keyId", "workspaceId", "role"],
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": ["api_key"]
                        },
                        "keyId": {
                          "type": "string"
                        },
                        "workspaceId": {
                          "type": "string"
                        },
                        "role": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns the signed-in user, or the API key workspace when the caller is a key.",
        "summary": "Get the caller",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon whoami"
      }
    },
    "/v1/me/notification-preferences": {
      "get": {
        "tags": ["Account"],
        "operationId": "get_notification_preferences",
        "parameters": [],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Personal notification preferences. They apply in every workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationPreferencesView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns personal notification preferences for the signed-in user. An API key cannot call it.",
        "summary": "Get notification preferences",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      },
      "patch": {
        "tags": ["Account"],
        "operationId": "update_notification_preferences",
        "parameters": [],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Personal notification preferences. They apply in every workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationPreferencesView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Updates personal notification preferences for the signed-in user. An API key cannot call it.",
        "summary": "Update notification preferences",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNotificationPreferencesRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      }
    },
    "/v1/workspaces": {
      "get": {
        "tags": ["Account"],
        "operationId": "list_workspaces",
        "parameters": [],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspaces for the signed-in user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountWorkspaceList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists workspaces for the signed-in user. An API key cannot call it.",
        "summary": "List workspaces",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon workspaces list"
      }
    },
    "/v1/workspaces/{workspaceId}/temporary-keys": {
      "post": {
        "tags": ["Account"],
        "operationId": "create_temporary_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "A 15-minute key for a signed-in CLI. Do not store it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["apiKey", "expiresAt"],
                  "properties": {
                    "apiKey": {
                      "type": "string",
                      "description": "A temporary key for the storage API. Send it as the Bearer token."
                    },
                    "expiresAt": {
                      "type": "string",
                      "description": "When the temporary key expires."
                    }
                  },
                  "additionalProperties": false,
                  "description": "A 15-minute key for a signed-in CLI. Do not store it.",
                  "title": "TemporaryKey"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns a 15-minute key for the storage API, for a signed-in CLI. It acts at your role. An API key cannot call this route: send the API key to the storage API instead.",
        "summary": "Mint a temporary key",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}": {
      "get": {
        "tags": ["Workspaces"],
        "operationId": "get_workspace",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace access result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns the workspace the caller can access, with its name and revision.",
        "summary": "Get a workspace",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon workspaces get"
      },
      "patch": {
        "tags": ["Workspaces"],
        "operationId": "update_workspace",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace access result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Changes the workspace name. Requires the admin role. Send the revision from a read: the update fails with a conflict when another writer changed the workspace first.",
        "summary": "Update a workspace",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkspaceUpdate"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      },
      "delete": {
        "tags": ["Workspaces"],
        "operationId": "delete_workspace",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace access result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Marks the workspace deleted and starts a seven-day recovery window. Requires the admin role. Every bucket must already be deleted. A restore keeps the members.",
        "summary": "Delete a workspace",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/restore": {
      "post": {
        "tags": ["Workspaces"],
        "operationId": "restore_workspace",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace access result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Restores a deleted workspace within its recovery window. Requires a signed-in user who was an admin when the workspace was deleted. Returns the same workspace id. An API key cannot call it.",
        "summary": "Restore a workspace",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/members": {
      "get": {
        "tags": ["Members"],
        "operationId": "list_members",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Case-insensitive substring match on a member's display name or email. Omit to list every member.",
              "examples": ["ada"]
            },
            "required": false,
            "description": "Case-insensitive substring match on a member's display name or email. Omit to list every member."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of memberships.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembershipList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists active members in the workspace. Requires the viewer role. Use query to filter by display name or email.",
        "summary": "List members",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon members list --query ada"
      }
    },
    "/v1/workspaces/{workspaceId}/members/{memberId}": {
      "patch": {
        "tags": ["Members"],
        "operationId": "update_member",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "memberId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The membership id.",
              "examples": ["memA1b2C3d4E5"]
            },
            "required": true,
            "description": "The membership id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One workspace membership.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembershipView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Changes a member's role. Requires the admin role. The last admin cannot become a viewer or editor.",
        "summary": "Update a member role",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMemberRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon members update mem_7Qp2 --role editor"
      },
      "delete": {
        "tags": ["Members"],
        "operationId": "remove_member",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "memberId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The membership id.",
              "examples": ["memA1b2C3d4E5"]
            },
            "required": true,
            "description": "The membership id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Removes a member from the workspace. Requires the admin role. The last admin cannot be removed. memberId cannot be me.",
        "summary": "Remove a member",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon members remove mem_7Qp2"
      }
    },
    "/v1/workspaces/{workspaceId}/members/{memberId}/api-keys": {
      "get": {
        "tags": ["Members"],
        "operationId": "list_member_api_keys",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "memberId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The membership id.",
              "examples": ["memA1b2C3d4E5"]
            },
            "required": true,
            "description": "The membership id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of API keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists personal API keys for another member. Requires the admin role. Secrets are never returned.",
        "summary": "List a member's API keys",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon members api-keys mem_7Qp2"
      }
    },
    "/v1/workspaces/{workspaceId}/invitations": {
      "get": {
        "tags": ["Invitations"],
        "operationId": "list_invitations",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of invitations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists pending invitations for the workspace. Requires the admin role.",
        "summary": "List invitations",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon invitations list"
      },
      "post": {
        "tags": ["Invitations"],
        "operationId": "create_invitations",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Per-address results from a batch invite.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["results"],
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InvitationBatchItem"
                      },
                      "description": "One result per submitted email, in request order."
                    }
                  },
                  "additionalProperties": false,
                  "description": "Per-address results from a batch invite.",
                  "title": "InvitationBatchResult",
                  "examples": [
                    {
                      "results": [
                        {
                          "email": "grace@example.com",
                          "outcome": "created",
                          "invitation": {
                            "id": "invC3d4E5f6G7",
                            "workspaceId": "wspq7ws2np5l8z4",
                            "email": "grace@example.com",
                            "role": "editor",
                            "state": "pending",
                            "delivery": "queued",
                            "expiresAt": "2026-09-21T18:00:00.000Z",
                            "revision": 1
                          }
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Invites one or more email addresses with the same role. Requires the admin role. Send between 1 and 50 addresses. Each address returns its own outcome.",
        "summary": "Invite members",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvitationsRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon invitations create --email ada@example.com --role editor"
      }
    },
    "/v1/workspaces/{workspaceId}/invitations/{invitationId}/resend": {
      "post": {
        "tags": ["Invitations"],
        "operationId": "resend_invitation",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "invitationId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The invitation id.",
              "examples": ["invC3d4E5f6G7"]
            },
            "required": true,
            "description": "The invitation id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One workspace invitation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Sends the invitation email again. Requires the admin role. The invitation must still be pending.",
        "summary": "Resend an invitation",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon invitations resend inv_3kR9"
      }
    },
    "/v1/workspaces/{workspaceId}/invitations/{invitationId}": {
      "patch": {
        "tags": ["Invitations"],
        "operationId": "update_invitation",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "invitationId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The invitation id.",
              "examples": ["invC3d4E5f6G7"]
            },
            "required": true,
            "description": "The invitation id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One workspace invitation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Changes the role on a pending invitation. Requires the admin role.",
        "summary": "Update an invitation role",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInvitationRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon invitations update inv_3kR9 --role viewer"
      },
      "delete": {
        "tags": ["Invitations"],
        "operationId": "revoke_invitation",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "invitationId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The invitation id.",
              "examples": ["invC3d4E5f6G7"]
            },
            "required": true,
            "description": "The invitation id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Revokes a pending invitation. Requires the admin role. This does not remove an accepted member.",
        "summary": "Revoke an invitation",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon invitations revoke inv_3kR9"
      }
    },
    "/v1/workspaces/{workspaceId}/api-keys": {
      "get": {
        "tags": ["API keys"],
        "operationId": "list_api_keys",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "owner",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["me", "workspace"],
              "description": "Which keys to list. Defaults to me. Only an Admin can list workspace keys.",
              "title": "ApiKeyOwner"
            },
            "required": false,
            "description": "Which keys to list. Defaults to me. Only an Admin can list workspace keys."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of API keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists API keys. owner=me returns the caller's personal keys and needs the viewer role. owner=workspace returns the workspace keys and requires the admin role. Keys are never returned, only masked keys.",
        "summary": "List API keys",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon api-keys list --owner workspace"
      },
      "post": {
        "tags": ["API keys"],
        "operationId": "create_api_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Create result. Store apiKey now. It is not shown again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["key", "apiKey"],
                  "properties": {
                    "key": {
                      "type": "object",
                      "required": [
                        "id",
                        "workspaceId",
                        "name",
                        "maskedKey",
                        "ownerKind",
                        "ownerUserId",
                        "createdByUserId",
                        "role",
                        "createdAt",
                        "lastUsedAt",
                        "expiresAt",
                        "revokedAt",
                        "revision"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The API key id."
                        },
                        "workspaceId": {
                          "type": "string",
                          "description": "The workspace id."
                        },
                        "name": {
                          "type": "string",
                          "description": "Display name."
                        },
                        "maskedKey": {
                          "type": "string",
                          "description": "The key with its secret part hidden, for example gak_GAK1a8Xk2mQ9pL0vT4cZ.••••. The visible part is the S3 access key ID."
                        },
                        "ownerKind": {
                          "type": "string",
                          "enum": ["user", "workspace"],
                          "description": "user for a personal key. workspace for a workspace key."
                        },
                        "ownerUserId": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "The member who owns a personal key. Null for a workspace key."
                        },
                        "createdByUserId": {
                          "type": "string",
                          "description": "The user who created the key."
                        },
                        "role": {
                          "type": "string",
                          "enum": ["viewer", "editor", "admin"],
                          "description": "Role granted by this key.",
                          "title": "Role"
                        },
                        "createdAt": {
                          "type": "string",
                          "description": "When the key was created, in UTC."
                        },
                        "lastUsedAt": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "When the key was last used, or null."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When the key was last used, or null."
                        },
                        "expiresAt": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "When the key expires, or null if it does not expire."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When the key expires, or null if it does not expire."
                        },
                        "revokedAt": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "When the key was revoked, or null."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When the key was revoked, or null."
                        },
                        "revision": {
                          "type": "number",
                          "description": "Monotonic API key revision."
                        }
                      },
                      "additionalProperties": false,
                      "description": "The new key record. It does not include the key.",
                      "title": "ApiKeyView",
                      "examples": [
                        {
                          "id": "apkE5f6G7h8I9",
                          "workspaceId": "wspq7ws2np5l8z4",
                          "name": "Local CLI",
                          "maskedKey": "gak_GAK1a8Xk2mQ9pL0vT4cZ.••••",
                          "ownerKind": "user",
                          "ownerUserId": "usrB2c3D4e5F6",
                          "createdByUserId": "usrB2c3D4e5F6",
                          "role": "viewer",
                          "createdAt": "2026-09-14T18:00:00.000Z",
                          "lastUsedAt": null,
                          "expiresAt": null,
                          "revokedAt": null,
                          "revision": 1
                        }
                      ]
                    },
                    "apiKey": {
                      "type": "string",
                      "description": "The API key. Shown once. Send it as the Bearer token. S3 tools use it as the secret access key; the access key ID is the part between \"_\" and \".\"."
                    }
                  },
                  "additionalProperties": false,
                  "description": "Create result. Store apiKey now. It is not shown again.",
                  "title": "CreatedApiKey",
                  "examples": [
                    {
                      "key": {
                        "id": "apkE5f6G7h8I9",
                        "workspaceId": "wspq7ws2np5l8z4",
                        "name": "Local CLI",
                        "maskedKey": "gak_GAK1a8Xk2mQ9pL0vT4cZ.••••",
                        "ownerKind": "user",
                        "ownerUserId": "usrB2c3D4e5F6",
                        "createdByUserId": "usrB2c3D4e5F6",
                        "role": "viewer",
                        "createdAt": "2026-09-14T18:00:00.000Z",
                        "lastUsedAt": null,
                        "expiresAt": null,
                        "revokedAt": null,
                        "revision": 1
                      },
                      "apiKey": "gak_GAK1a8Xk2mQ9pL0vT4cZ.<shown once>"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Creates a personal API key for the caller, or a workspace key when owner is workspace. A viewer can create a personal key. An admin is required for a workspace key. The key works on the API, the storage API, and S3 tools. It appears once.",
        "summary": "Create an API key",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon api-keys create --name ingest-bot"
      }
    },
    "/v1/workspaces/{workspaceId}/api-keys/{keyId}": {
      "get": {
        "tags": ["API keys"],
        "operationId": "get_api_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "keyId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The API key id.",
              "examples": ["keyE5f6G7h8I9"]
            },
            "required": true,
            "description": "The API key id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One API key. The key itself is never included.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns one API key without the key itself. The owner can read a personal key. An admin can read any key in the workspace.",
        "summary": "Get an API key",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon api-keys get gak_1a8Xk2mQ"
      },
      "patch": {
        "tags": ["API keys"],
        "operationId": "update_api_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "keyId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The API key id.",
              "examples": ["keyE5f6G7h8I9"]
            },
            "required": true,
            "description": "The API key id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One API key. The key itself is never included.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Edits the name or role. The key stays the same.",
        "summary": "Update an API key",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateApiKeyRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon api-keys update gak_1a8Xk2mQ --role viewer"
      },
      "delete": {
        "tags": ["API keys"],
        "operationId": "revoke_api_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "keyId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The API key id.",
              "examples": ["keyE5f6G7h8I9"]
            },
            "required": true,
            "description": "The API key id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Revokes an API key. The owner can revoke their own personal key. An admin can revoke any key in the workspace. Storage rejects the key when this call returns.",
        "summary": "Revoke an API key",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon api-keys revoke gak_1a8Xk2mQ"
      }
    },
    "/v1/workspaces/{workspaceId}/datasets": {
      "get": {
        "tags": ["Datasets"],
        "operationId": "list_datasets",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["legal", "commerce", "people", "government", "science", "other"],
              "description": "Only this category."
            },
            "required": false,
            "description": "Only this category."
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Words of the title or the summary.",
              "title": "maxLength(200)",
              "maxLength": 200
            },
            "required": false,
            "description": "Words of the title or the summary."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "nextCursor from the previous page."
            },
            "required": false,
            "description": "nextCursor from the previous page."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "a string to be decoded into a number"
            },
            "required": false,
            "description": "a string to be decoded into a number"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One page of the dataset catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DatasetList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns the published datasets, most recently indexed first, with what the calling workspace can do with each one. A dataset is free, or paid: a paid dataset says locked until the workspace has access. A dataset is not a bucket: it counts toward no storage, and a query of it counts like a query of a bucket. Requires the viewer role.",
        "summary": "List datasets",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon datasets list --category legal"
      }
    },
    "/v1/workspaces/{workspaceId}/datasets/{datasetId}": {
      "get": {
        "tags": ["Datasets"],
        "operationId": "get_dataset",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "datasetId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The dataset id (dst…) or its slug.",
              "examples": ["dstC4s3L4w0x1"]
            },
            "required": true,
            "description": "The dataset id (dst…) or its slug."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A read-only set of documents that Graphon curates. Every workspace can query a dataset by its id, with the same routes as a bucket. It holds no storage of the workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dataset"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns one published dataset by its id or its slug: its description, size, source, license, examples, and access. A draft, retired, or unknown dataset is 404 not_found. Requires the viewer role.",
        "summary": "Get a dataset",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon datasets get us-case-law"
      }
    },
    "/v1/workspaces/{workspaceId}/search": {
      "post": {
        "tags": ["Search"],
        "operationId": "search_objects",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked results. Read spans with Read spans, or the whole object from the storage API with its key and versionId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Ranks the objects or passages of one target against a text. The target is a bucket with indexing enabled, or a dataset from List datasets. Each result is an object and the spans in it that matched: pages of a document, characters of a text file, or seconds of a video or a recording. A span holds no text: read it with Read spans. Read the whole object of a bucket from the storage API with its key and versionId. Scope the search with keys, keyPrefix, or a metadata filter. Requires the viewer role. An empty bucket returns no results and the warning index_empty. Nothing is stored.",
        "summary": "Search objects",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon search support-tickets \"connection pool\" --limit 20"
      }
    },
    "/v1/workspaces/{workspaceId}/read-spans": {
      "post": {
        "tags": ["Search"],
        "operationId": "read_spans",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The content of each span, in the parts that include names. One part stops at 50,000 characters of text, 500 pages, or 600 seconds. next is the body of the next read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadSpansResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns the content of 1 to 50 spans that Search objects, Answer a question, or a run returned, with one result for each span, in order. include names the parts: text (the default) is the text of a document, or the speech of a video or a recording with its lines. raw is the span cut from the object in its own format: a PDF of the pages, the text of a text file or a mail, the image, or a clip. object is the whole object version. delivery inline (the default) returns binary parts as base64 data, up to 20 MiB a call, and a url past that. url returns every binary part as a url, which works until its expiresAt. A large span returns in parts: the result span is the part returned, and next is the body of the next read, or null. A span that cannot be read has an error on its own result: not_found, invalid_span (the span does not fit the object), or content_unavailable (the content is not stored or cannot be read). The other spans still read. Requires the viewer role. Send the target of the search: a bucket or a dataset.",
        "summary": "Read spans",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadSpansRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon read-spans support-tickets manuals/pump.pdf --version-id ver_8a1d4c7e2b9f4e6a8c3d5b7f1e9a2c4d --unit chars --start 1200 --end 3400 --include text"
      }
    },
    "/v1/workspaces/{workspaceId}/buckets/{bucketId}/metadata-fields": {
      "get": {
        "tags": ["Metadata fields"],
        "operationId": "get_metadata_fields",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id. The bucket must have indexing enabled.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id. The bucket must have indexing enabled."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The metadata fields of a bucket: the metadata keys that a filter can read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataFields"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns the metadata fields of a bucket: each metadata key that a filter can read, its type, whether it is ready or still indexing, and how many objects hold a value that does not fit the type. A new bucket lists no fields. Requires the viewer role. The bucket must have indexing enabled. The fields work before the first upload and while objects index.",
        "summary": "Get metadata fields",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon buckets metadata-fields get support-tickets"
      },
      "patch": {
        "tags": ["Metadata fields"],
        "operationId": "update_metadata_fields",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "bucketId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The bucket id. The bucket must have indexing enabled.",
              "examples": ["bktA1b2C3d4E5"]
            },
            "required": true,
            "description": "The bucket id. The bucket must have indexing enabled."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The metadata fields of a bucket: the metadata keys that a filter can read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataFields"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists, retypes, or removes metadata fields of a bucket, and returns every field. A key left out keeps its setting, and null removes the field. A filter can read only a listed field. On a bucket with objects, a changed field is indexing while the index is rewritten, which takes up to about 30 minutes; list fields before the first upload to skip the wait. Other fields and queries without a filter keep working meanwhile. A change while the last one is still indexing fails with operation_in_progress. Requires the editor role. The bucket must have indexing enabled. The fields work before the first upload and while objects index.",
        "summary": "Update metadata fields",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMetadataFieldsRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon buckets metadata-fields set support-tickets --field team=text --field year=number --remove old_tag"
      }
    },
    "/v1/workspaces/{workspaceId}/answer": {
      "post": {
        "tags": ["Answer"],
        "operationId": "answer_question",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The answer and its sources.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnswerResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Answers a question about one target, with a citation marker for each source. The target is a bucket with indexing enabled, or a dataset from List datasets. Usually seconds. The call returns an answer or an error within about 2 minutes. The call waits for the answer and stores nothing. sources picks all, cited, or no sources. Scope the question with keys, keyPrefix, or a metadata filter. Requires the viewer role. An image is a premium feature.",
        "summary": "Answer a question",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnswerRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon ask support-tickets \"Why did checkout stall?\""
      }
    },
    "/v1/workspaces/{workspaceId}/research": {
      "post": {
        "tags": ["Research"],
        "operationId": "start_research",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Server-sent events. run.created (the run, running) is always event 1. run.progress has stage, label, step, and totalSteps. run.succeeded or run.failed (the whole run) is the last event. A `: ping` comment comes every 15 seconds.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-sent events. run.created (the run, running) is always event 1. run.progress has stage, label, step, and totalSteps. run.succeeded or run.failed (the whole run) is the last event. A `: ping` comment comes every 15 seconds.",
                  "examples": [
                    "id: 1\nevent: run.created\ndata: {\"run\":{\"id\":\"rscR7tY2kL9mP\",\"status\":\"running\"}}\n\nid: 2\nevent: run.progress\ndata: {\"stage\":\"retrieval\",\"label\":\"Finding passages\",\"step\":1,\"totalSteps\":3}\n\n"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "One query run.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["research"],
                  "properties": {
                    "research": {
                      "$ref": "#/components/schemas/QueryRun"
                    }
                  },
                  "additionalProperties": false,
                  "description": "One query run.",
                  "title": "ResearchEnvelope",
                  "examples": [
                    {
                      "research": {
                        "id": "rscR7tY2kL9mP",
                        "workspaceId": "wsp4k9m2x7q1z8r",
                        "target": "bktA1b2C3d4E5",
                        "status": "succeeded",
                        "query": "Why did checkout stall after the 3 October deploy?",
                        "history": [],
                        "keys": [],
                        "keyPrefix": null,
                        "filter": null,
                        "answer": "Release 4.18 raised checkout workers from 8 to 24 but left the database pool at 200 [[SRC:0001]].",
                        "sources": [
                          {
                            "ref": "SRC:0001",
                            "key": "incidents/2026-10-03-checkout.pdf",
                            "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                            "contentType": "application/pdf",
                            "score": 0.86,
                            "cited": true,
                            "span": {
                              "key": "incidents/2026-10-03-checkout.pdf",
                              "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                              "unit": "pages",
                              "start": 2,
                              "end": 3
                            }
                          }
                        ],
                        "sourcesNextCursor": null,
                        "warnings": [],
                        "error": null,
                        "imageDescription": null,
                        "createdBy": {
                          "userId": null,
                          "apiKeyId": "apkH3sK8pW2xQ"
                        },
                        "createdAt": "2026-10-12T09:00:00.000Z",
                        "completedAt": "2026-10-12T09:03:42.210Z",
                        "expiresAt": "2026-10-19T09:03:42.210Z"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Starts a premium research run on one target: a bucket with indexing enabled, or a dataset from List datasets. Use it when one search is not enough, and the answer needs several steps. Minutes. At most 600 seconds. It returns at once with status running. It never waits for the answer: follow the run with Research events, and read it with Get research until expiresAt. The run belongs to the calling workspace. Scope the question with keys, keyPrefix, or a metadata filter. Ask a question that one pass can answer with Answer a question. Requires the viewer role. An image is a premium feature.",
        "summary": "Start research",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartResearchRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon research start support-tickets \"Every checkout timeout\" --mode recall"
      }
    },
    "/v1/workspaces/{workspaceId}/research/{researchId}": {
      "get": {
        "tags": ["Research"],
        "operationId": "get_research",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "researchId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The query run id.",
              "examples": ["rscR7tY2kL9mP"]
            },
            "required": true,
            "description": "The query run id."
          },
          {
            "name": "sources",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["all", "cited"],
              "description": "cited: only the sources that the answer cites. all: every source of the run: cited sources first, in the order the answer cites them, then the sources it only retrieved. Defaults to all."
            },
            "required": false,
            "description": "cited: only the sources that the answer cites. all: every source of the run: cited sources first, in the order the answer cites them, then the sources it only retrieved. Defaults to all."
          },
          {
            "name": "sourceLimit",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Sources on one page, 1 to 200. Defaults to 50. A smaller page keeps a tool result under its size limit.",
              "title": "between(1, 200)"
            },
            "required": false,
            "description": "Sources on one page, 1 to 200. Defaults to 50. A smaller page keeps a tool result under its size limit."
          },
          {
            "name": "sourceCursor",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The sourcesNextCursor of the previous read, to read the next page of sources. Send the same sources and sourceLimit. Defaults to the first page."
            },
            "required": false,
            "description": "The sourcesNextCursor of the previous read, to read the next page of sources. Send the same sources and sourceLimit. Defaults to the first page."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One query run.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResearchEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns a research run as it stands, at once. It never waits. A finished run stays readable until expiresAt, seven days past the end, also while its bucket is offline. After that it is 404 not_found. Use sources and sourceLimit to read fewer sources at a time, and sourceCursor to read the next page. Requires the viewer role.",
        "summary": "Get research",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon research get rscR7tY2kL9mP"
      }
    },
    "/v1/workspaces/{workspaceId}/research/{researchId}/events": {
      "get": {
        "tags": ["Research"],
        "operationId": "get_research_events",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "researchId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The query run id.",
              "examples": ["rscR7tY2kL9mP"]
            },
            "required": true,
            "description": "The query run id."
          },
          {
            "name": "last-event-id",
            "in": "header",
            "schema": {
              "type": "string",
              "description": "a string to be decoded into a number"
            },
            "required": false,
            "description": "a string to be decoded into a number"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Server-sent events. run.created (the run, running) is always event 1. run.progress has stage, label, step, and totalSteps. run.succeeded or run.failed (the whole run) is the last event. A `: ping` comment comes every 15 seconds.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-sent events. run.created (the run, running) is always event 1. run.progress has stage, label, step, and totalSteps. run.succeeded or run.failed (the whole run) is the last event. A `: ping` comment comes every 15 seconds.",
                  "examples": [
                    "id: 1\nevent: run.created\ndata: {\"run\":{\"id\":\"rscR7tY2kL9mP\",\"status\":\"running\"}}\n\nid: 2\nevent: run.progress\ndata: {\"stage\":\"retrieval\",\"label\":\"Finding passages\",\"step\":1,\"totalSteps\":3}\n\n"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Streams the events of a query run as server-sent events until the run ends, then closes. Send Last-Event-ID to get only later events. A run that has ended sends its events at once and closes, until expiresAt. A stream closes after 55 minutes: rejoin with Last-Event-ID, and no event is missed. Requires the viewer role.",
        "summary": "Research events",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks": {
      "get": {
        "tags": ["Webhooks"],
        "operationId": "list_webhooks",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "owner",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["me", "workspace"],
              "description": "Narrows the list. Without it, a member sees their own webhooks, a workspace key sees workspace webhooks, and an Admin sees every webhook.",
              "title": "WebhookOwner"
            },
            "required": false,
            "description": "Narrows the list. Without it, a member sees their own webhooks, a workspace key sees workspace webhooks, and an Admin sees every webhook."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists the webhooks the caller can see, newest first. A member sees their own, a workspace key sees workspace webhooks, and an Admin sees every webhook. Signing secrets are never returned.",
        "summary": "List webhooks",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks list"
      },
      "post": {
        "tags": ["Webhooks"],
        "operationId": "create_webhook",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Store the secret now. It is not shown again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["webhook", "secret"],
                  "properties": {
                    "webhook": {
                      "$ref": "#/components/schemas/WebhookView"
                    },
                    "secret": {
                      "type": "string",
                      "description": "The signing secret, whsec_ and base64. Shown once. Check each POST with a Standard Webhooks library."
                    }
                  },
                  "additionalProperties": false,
                  "description": "Store the secret now. It is not shown again.",
                  "title": "CreatedWebhook",
                  "examples": [
                    {
                      "webhook": {
                        "id": "whkN4vB7qX2mZ",
                        "workspaceId": "wspq7ws2np5l8z4",
                        "name": "indexing-callbacks",
                        "url": "https://hooks.example.com/graphon",
                        "eventTypes": ["object.indexed", "object.indexing_failed"],
                        "bucketIds": null,
                        "enabled": true,
                        "disabledReason": null,
                        "ownerKind": "user",
                        "ownerUserId": "usrB2c3D4e5F6",
                        "signing": {
                          "secretFingerprint": "sha256:9b2d44f0",
                          "previousSecretFingerprint": null,
                          "previousSecretExpiresAt": null
                        },
                        "delivery": {
                          "pendingDeliveries": 0,
                          "lastSucceededAt": "2026-10-14T09:05:13.004Z",
                          "lastFailedAt": null
                        },
                        "createdBy": {
                          "userId": "usrB2c3D4e5F6",
                          "apiKeyId": null
                        },
                        "createdAt": "2026-10-14T09:00:00.000Z",
                        "updatedAt": "2026-10-14T09:00:00.000Z"
                      },
                      "secret": "whsec_<shown once>"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Registers an HTTPS receiver for the events of the workspace, optionally only some event types and buckets. Any member can make a personal webhook. A workspace key makes a workspace webhook. The signing secret appears once.",
        "summary": "Create a webhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks create --name orders --url https://example.com/graphon --event-type object.indexed --write-env .env"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks/{webhookId}": {
      "get": {
        "tags": ["Webhooks"],
        "operationId": "get_webhook",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One webhook. The signing secret is never included.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns one webhook with its status and a summary of its delivery log. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Get a webhook",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks get whkN4vB7qX2mZ"
      },
      "patch": {
        "tags": ["Webhooks"],
        "operationId": "update_webhook",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One webhook. The signing secret is never included.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Changes the name, URL, event types, buckets, or enabled. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Update a webhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks update whkN4vB7qX2mZ --disable"
      },
      "delete": {
        "tags": ["Webhooks"],
        "operationId": "delete_webhook",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Deletes the webhook and its delivery log. To stop deliveries and keep the log, set enabled to false. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Delete a webhook",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks delete whkN4vB7qX2mZ"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks/{webhookId}/rotate-secret": {
      "post": {
        "tags": ["Webhooks"],
        "operationId": "rotate_webhook_secret",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Store the secret now. It is not shown again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedWebhook"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Makes a new signing secret and shows it once. The previous secret keeps signing for the overlap, 24 hours by default. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Rotate a webhook secret",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotateWebhookSecretRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks rotate-secret whkN4vB7qX2mZ --previous-expires-in 86400 --write-env .env"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks/{webhookId}/test": {
      "post": {
        "tags": ["Webhooks"],
        "operationId": "test_webhook",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The result of one webhook.test POST.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestResult"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Sends one signed webhook.test POST to the receiver now, and returns its response. It works while the webhook is off, and the log does not keep it. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Test a webhook",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks test whkN4vB7qX2mZ"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks/{webhookId}/deliveries": {
      "get": {
        "tags": ["Webhooks"],
        "operationId": "list_webhook_deliveries",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "pending, succeeded, or failed."
            },
            "required": false,
            "description": "pending, succeeded, or failed."
          },
          {
            "name": "eventType",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "One event type."
            },
            "required": false,
            "description": "One event type."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Items on one page. Default 100."
            },
            "required": false,
            "description": "Items on one page. Default 100."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "nextCursor of the previous page, with the same filters."
            },
            "required": false,
            "description": "nextCursor of the previous page, with the same filters."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the delivery log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Lists the delivery log, newest first: each event the webhook got, its status, and its last attempt. The log keeps 30 days. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "List webhook deliveries",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks deliveries whkN4vB7qX2mZ --status failed"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks/{webhookId}/deliveries/{eventId}": {
      "get": {
        "tags": ["Webhooks"],
        "operationId": "get_webhook_delivery",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          },
          {
            "name": "eventId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The event id. It is the webhook-id header of each POST.",
              "examples": ["evtW2nC6vJ0hS"]
            },
            "required": true,
            "description": "The event id. It is the webhook-id header of each POST."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One event at one webhook, with its body and every attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryDetail"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Returns one event at one webhook: the exact body Graphon sends and every attempt. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Get a webhook delivery",
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks delivery whkN4vB7qX2mZ evtK5mP9qL3dF"
      }
    },
    "/v1/workspaces/{workspaceId}/webhooks/{webhookId}/replay": {
      "post": {
        "tags": ["Webhooks"],
        "operationId": "replay_webhook_deliveries",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspq7ws2np5l8z4"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "webhookId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The webhook id.",
              "examples": ["whkN4vB7qX2mZ"]
            },
            "required": true,
            "description": "The webhook id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "The replay result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["queued"],
                  "properties": {
                    "queued": {
                      "type": "number",
                      "description": "Deliveries queued again."
                    }
                  },
                  "additionalProperties": false,
                  "description": "The replay result.",
                  "title": "ReplayWebhookDeliveriesResult",
                  "examples": [
                    {
                      "queued": 42
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid. A body field that the route does not take is invalid, and the message names it. invalid_filter names the metadata field in details.field, and why in details.reason."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role, the bucket is offline, or the dataset is paid and the workspace has no access to it."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request conflicts with the current state, such as the last admin, a bucket that is not active, an index that is not ready, or a metadata field that is still indexing."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than the route's limit. Most routes take 16,384 bytes."
                }
              }
            }
          },
          "503": {
            "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "A service that this request needs is busy or did not answer in time. Send the same request again after the Retry-After seconds."
                }
              }
            }
          }
        },
        "description": "Sends past events of this webhook again, by event id or by time range, with the same id and body. A member manages their own webhooks, a workspace key manages workspace webhooks, and an Admin manages every webhook.",
        "summary": "Replay webhook deliveries",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplayWebhookDeliveriesRequest"
              }
            }
          },
          "required": true
        },
        "x-graphon-phase": 1,
        "x-graphon-mode": "real",
        "x-cli-example": "graphon webhooks replay whkN4vB7qX2mZ --since 2026-10-14T00:00:00Z --only-failed"
      }
    }
  },
  "components": {
    "schemas": {
      "ApiError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "retryable"],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable error token such as unauthenticated or invalid_request."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation."
              },
              "requestId": {
                "type": "string",
                "description": "Reference for this request. The same value is in the x-request-id header."
              },
              "retryable": {
                "type": "boolean",
                "description": "True when the same request can work later with no change. Then the response also has Retry-After and details.retryAfterSeconds. False when the same request gets the same error."
              },
              "details": {
                "type": "object",
                "required": [],
                "properties": {
                  "retryAfterSeconds": {
                    "type": "integer",
                    "description": "For a retryable error: the seconds to wait before the same request. The Retry-After header has the same value.",
                    "title": "int"
                  },
                  "feature": {
                    "type": "string",
                    "description": "For feature_not_in_plan: the premium feature that the workspace's plan lacks."
                  },
                  "target": {
                    "type": "string",
                    "description": "For dataset_access_required: the paid dataset that the workspace has no access to."
                  },
                  "field": {
                    "type": "string",
                    "description": "The field that the error is about, such as the metadata field of invalid_filter or metadata_field_indexing."
                  },
                  "reason": {
                    "type": "string",
                    "description": "For invalid_filter: not_listed (the bucket does not list the field), op_not_allowed (its type does not take the operator), or invalid_value (the value does not fit its type)."
                  }
                },
                "additionalProperties": false,
                "description": "More about the error. Each field is optional."
              }
            },
            "additionalProperties": false,
            "description": "Machine-readable failure."
          }
        },
        "additionalProperties": false,
        "description": "Error body returned by the API. error.requestId matches the x-request-id header.",
        "title": "ApiError"
      },
      "NotificationPreferencesView": {
        "type": "object",
        "required": [
          "inApp",
          "email",
          "critical",
          "warning",
          "storageQuota",
          "workspaceUpdates",
          "productUpdates",
          "revision"
        ],
        "properties": {
          "inApp": {
            "type": "boolean",
            "description": "Show notices in the Graphon inbox."
          },
          "email": {
            "type": "boolean",
            "description": "Send optional notices to the account email."
          },
          "critical": {
            "type": "boolean",
            "description": "Receive critical alert notices."
          },
          "warning": {
            "type": "boolean",
            "description": "Receive warning alert notices."
          },
          "storageQuota": {
            "type": "boolean",
            "description": "Receive usage and quota notices."
          },
          "workspaceUpdates": {
            "type": "boolean",
            "description": "Receive workspace update notices."
          },
          "productUpdates": {
            "type": "boolean",
            "description": "Receive product update notices."
          },
          "revision": {
            "type": "number",
            "description": "Preference row revision."
          }
        },
        "additionalProperties": false,
        "description": "Personal notification preferences. They apply in every workspace.",
        "title": "NotificationPreferencesView"
      },
      "UpdateNotificationPreferencesRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "inApp": {
            "type": "boolean",
            "description": "Show notices in the Graphon inbox."
          },
          "email": {
            "type": "boolean",
            "description": "Send optional notices to the account email."
          },
          "critical": {
            "type": "boolean",
            "description": "Receive critical alert notices."
          },
          "warning": {
            "type": "boolean",
            "description": "Receive warning alert notices."
          },
          "storageQuota": {
            "type": "boolean",
            "description": "Receive usage and quota notices."
          },
          "workspaceUpdates": {
            "type": "boolean",
            "description": "Receive workspace update notices."
          },
          "productUpdates": {
            "type": "boolean",
            "description": "Receive product update notices."
          }
        },
        "additionalProperties": false,
        "description": "Fields to change on personal notification preferences.",
        "title": "UpdateNotificationPreferencesRequest"
      },
      "AccountWorkspaceList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountWorkspace"
            },
            "description": "Workspaces the signed-in user can open."
          }
        },
        "additionalProperties": false,
        "description": "Workspaces for the signed-in user.",
        "title": "AccountWorkspaceList"
      },
      "AccountWorkspace": {
        "type": "object",
        "required": ["id", "name", "role"],
        "properties": {
          "id": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "The workspace name."
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          }
        },
        "additionalProperties": false,
        "description": "A workspace the signed-in user can open.",
        "title": "AccountWorkspace"
      },
      "Role": {
        "type": "string",
        "enum": ["viewer", "editor", "admin"],
        "description": "Workspace role. A personal key cannot exceed its member's role.",
        "title": "Role"
      },
      "WorkspaceView": {
        "type": "object",
        "required": ["id", "name", "revision"],
        "properties": {
          "id": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "The workspace name."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic workspace revision. Send it back to update the workspace."
          }
        },
        "additionalProperties": false,
        "description": "Workspace access result.",
        "title": "WorkspaceView",
        "examples": [
          {
            "id": "wspq7ws2np5l8z4",
            "name": "Ada Lovelace’s workspace",
            "revision": 1
          }
        ]
      },
      "WorkspaceUpdate": {
        "type": "object",
        "required": ["name", "revision"],
        "properties": {
          "name": {
            "type": "string",
            "description": "The new workspace name. 1 to 100 characters after trimming."
          },
          "revision": {
            "type": "number",
            "description": "The revision the caller read. The update fails when the workspace changed after that read."
          }
        },
        "additionalProperties": false,
        "description": "Workspace fields to change.",
        "title": "WorkspaceUpdate",
        "examples": [
          {
            "name": "Research",
            "revision": 1
          }
        ]
      },
      "MembershipList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipView"
            },
            "description": "Membership rows."
          }
        },
        "additionalProperties": false,
        "description": "A list of memberships.",
        "title": "MembershipList",
        "examples": [
          {
            "items": [
              {
                "id": "memA1b2C3d4E5",
                "workspaceId": "wspq7ws2np5l8z4",
                "userId": "usrB2c3D4e5F6",
                "displayName": "Ada Lovelace",
                "email": "ada@example.com",
                "role": "admin",
                "status": "active",
                "joinedAt": "2026-09-14T18:00:00.000Z",
                "revision": 1
              }
            ]
          }
        ]
      },
      "MembershipView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "userId",
          "displayName",
          "email",
          "role",
          "status",
          "joinedAt",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The membership id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "userId": {
            "type": "string",
            "description": "The member's user id."
          },
          "displayName": {
            "type": "string",
            "description": "The member's display name."
          },
          "email": {
            "type": "string",
            "description": "The member's email."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "The member's workspace role.",
            "title": "Role"
          },
          "status": {
            "type": "string",
            "enum": ["active", "retained", "left", "removed"],
            "description": "Membership state."
          },
          "joinedAt": {
            "type": "string",
            "description": "When the member joined, in UTC."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic membership revision."
          }
        },
        "additionalProperties": false,
        "description": "One workspace membership.",
        "title": "MembershipView",
        "examples": [
          {
            "id": "memA1b2C3d4E5",
            "workspaceId": "wspq7ws2np5l8z4",
            "userId": "usrB2c3D4e5F6",
            "displayName": "Ada Lovelace",
            "email": "ada@example.com",
            "role": "admin",
            "status": "active",
            "joinedAt": "2026-09-14T18:00:00.000Z",
            "revision": 1
          }
        ]
      },
      "UpdateMemberRequest": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "New role for the member.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Role change for a member.",
        "title": "UpdateMemberRequest",
        "examples": [
          {
            "role": "editor"
          }
        ]
      },
      "ApiKeyList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKeyView"
            },
            "description": "API key rows without the keys."
          }
        },
        "additionalProperties": false,
        "description": "A list of API keys.",
        "title": "ApiKeyList",
        "examples": [
          {
            "items": [
              {
                "id": "apkE5f6G7h8I9",
                "workspaceId": "wspq7ws2np5l8z4",
                "name": "Local CLI",
                "maskedKey": "gak_GAK1a8Xk2mQ9pL0vT4cZ.••••",
                "ownerKind": "user",
                "ownerUserId": "usrB2c3D4e5F6",
                "createdByUserId": "usrB2c3D4e5F6",
                "role": "viewer",
                "createdAt": "2026-09-14T18:00:00.000Z",
                "lastUsedAt": null,
                "expiresAt": null,
                "revokedAt": null,
                "revision": 1
              }
            ]
          }
        ]
      },
      "ApiKeyView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "maskedKey",
          "ownerKind",
          "ownerUserId",
          "createdByUserId",
          "role",
          "createdAt",
          "lastUsedAt",
          "expiresAt",
          "revokedAt",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The API key id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "maskedKey": {
            "type": "string",
            "description": "The key with its secret part hidden, for example gak_GAK1a8Xk2mQ9pL0vT4cZ.••••. The visible part is the S3 access key ID."
          },
          "ownerKind": {
            "type": "string",
            "enum": ["user", "workspace"],
            "description": "user for a personal key. workspace for a workspace key."
          },
          "ownerUserId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The member who owns a personal key. Null for a workspace key."
          },
          "createdByUserId": {
            "type": "string",
            "description": "The user who created the key."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role granted by this key.",
            "title": "Role"
          },
          "createdAt": {
            "type": "string",
            "description": "When the key was created, in UTC."
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the key was last used, or null."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key was last used, or null."
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the key expires, or null if it does not expire."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key expires, or null if it does not expire."
          },
          "revokedAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the key was revoked, or null."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key was revoked, or null."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic API key revision."
          }
        },
        "additionalProperties": false,
        "description": "One API key. The key itself is never included.",
        "title": "ApiKeyView",
        "examples": [
          {
            "id": "apkE5f6G7h8I9",
            "workspaceId": "wspq7ws2np5l8z4",
            "name": "Local CLI",
            "maskedKey": "gak_GAK1a8Xk2mQ9pL0vT4cZ.••••",
            "ownerKind": "user",
            "ownerUserId": "usrB2c3D4e5F6",
            "createdByUserId": "usrB2c3D4e5F6",
            "role": "viewer",
            "createdAt": "2026-09-14T18:00:00.000Z",
            "lastUsedAt": null,
            "expiresAt": null,
            "revokedAt": null,
            "revision": 1
          }
        ]
      },
      "InvitationList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvitationView"
            },
            "description": "Invitation rows."
          }
        },
        "additionalProperties": false,
        "description": "A list of invitations.",
        "title": "InvitationList",
        "examples": [
          {
            "items": [
              {
                "id": "invC3d4E5f6G7",
                "workspaceId": "wspq7ws2np5l8z4",
                "email": "grace@example.com",
                "role": "editor",
                "state": "pending",
                "delivery": "queued",
                "expiresAt": "2026-09-21T18:00:00.000Z",
                "revision": 1
              }
            ]
          }
        ]
      },
      "InvitationView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "email",
          "role",
          "state",
          "delivery",
          "expiresAt",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The invitation id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "email": {
            "type": "string",
            "description": "The invited email."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role the person receives if they accept.",
            "title": "Role"
          },
          "state": {
            "type": "string",
            "enum": ["pending", "accepted", "revoked", "expired"],
            "description": "Invitation lifecycle state."
          },
          "delivery": {
            "type": "string",
            "enum": ["queued", "sent", "failed"],
            "description": "Email delivery state."
          },
          "expiresAt": {
            "type": "string",
            "description": "When the invitation expires, in UTC."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic invitation revision."
          }
        },
        "additionalProperties": false,
        "description": "One workspace invitation.",
        "title": "InvitationView",
        "examples": [
          {
            "id": "invC3d4E5f6G7",
            "workspaceId": "wspq7ws2np5l8z4",
            "email": "grace@example.com",
            "role": "editor",
            "state": "pending",
            "delivery": "queued",
            "expiresAt": "2026-09-21T18:00:00.000Z",
            "revision": 1
          }
        ]
      },
      "CreateInvitationsRequest": {
        "type": "object",
        "required": ["emails", "role"],
        "properties": {
          "emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Email addresses to invite. Send 1 to 50 addresses."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role granted when the person accepts.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Batch invite payload.",
        "title": "CreateInvitationsRequest",
        "examples": [
          {
            "emails": ["grace@example.com"],
            "role": "editor"
          }
        ]
      },
      "InvitationBatchItem": {
        "type": "object",
        "required": ["email", "outcome", "invitation"],
        "properties": {
          "email": {
            "type": "string",
            "description": "The submitted email."
          },
          "outcome": {
            "type": "string",
            "enum": ["created", "resent", "already_member", "pending_other_role"],
            "description": "What happened for this address."
          },
          "invitation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/InvitationView"
              },
              {
                "type": "null"
              }
            ],
            "description": "The invitation when one was created or updated. Null when the address is already a member."
          }
        },
        "additionalProperties": false,
        "description": "Invite result for one email.",
        "title": "InvitationBatchItem"
      },
      "UpdateInvitationRequest": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "New role for the pending invitation.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Role change for a pending invitation.",
        "title": "UpdateInvitationRequest",
        "examples": [
          {
            "role": "viewer"
          }
        ]
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "owner": {
            "type": "string",
            "enum": ["me", "workspace"],
            "description": "Who owns the key. Defaults to me.",
            "title": "ApiKeyOwner"
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role for the new key. It cannot exceed your role. Defaults to your role for a personal key and to viewer for a workspace key.",
            "title": "Role"
          },
          "expiresAt": {
            "type": "string",
            "description": "Optional expiry in UTC. The time must be in the future."
          }
        },
        "additionalProperties": false,
        "description": "Create payload for an API key.",
        "title": "CreateApiKeyRequest",
        "examples": [
          {
            "name": "Local CLI"
          },
          {
            "name": "ingest-bot",
            "owner": "workspace",
            "role": "editor"
          }
        ]
      },
      "UpdateApiKeyRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "New role. It cannot exceed the key owner's role or your role.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Edit the name or role. The key stays the same.",
        "title": "UpdateApiKeyRequest",
        "examples": [
          {
            "name": "Local CLI",
            "role": "editor"
          }
        ]
      },
      "DatasetList": {
        "type": "object",
        "required": ["datasets", "nextCursor"],
        "properties": {
          "datasets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Dataset"
            },
            "description": "Most recently indexed first."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The cursor of the next page. Null on the last page."
          }
        },
        "additionalProperties": false,
        "description": "One page of the dataset catalog.",
        "title": "DatasetList",
        "examples": [
          {
            "datasets": [
              {
                "id": "dstC4s3L4w0x1",
                "slug": "us-case-law",
                "title": "US case law",
                "summary": "Opinions of the US Supreme Court and the federal courts of appeals.",
                "description": "Every published opinion of the US Supreme Court since 1950, and of the federal courts of appeals since 2000, as plain text.",
                "category": "legal",
                "source": {
                  "name": "CourtListener",
                  "url": "https://www.courtlistener.com",
                  "license": "Public domain"
                },
                "documentCount": 412904,
                "indexedBytes": "8392045113",
                "indexedAt": "2026-10-26T04:12:00.000Z",
                "examples": [
                  {
                    "query": "Which cases overruled Chevron?",
                    "mode": "answer"
                  }
                ],
                "access": {
                  "price": {
                    "kind": "free"
                  },
                  "state": "open"
                }
              }
            ],
            "nextCursor": null
          }
        ]
      },
      "Dataset": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "title",
          "summary",
          "description",
          "category",
          "source",
          "documentCount",
          "indexedBytes",
          "indexedAt",
          "examples",
          "access"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The dataset id: dst and 10 characters. Send it as target to query the dataset."
          },
          "slug": {
            "type": "string",
            "description": "A short readable name. Get a dataset takes it."
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string",
            "description": "One line, at most 160 characters."
          },
          "description": {
            "type": "string",
            "description": "At most 2,000 characters."
          },
          "category": {
            "type": "string",
            "enum": ["legal", "commerce", "people", "government", "science", "other"]
          },
          "source": {
            "type": "object",
            "required": ["name", "url", "license"],
            "properties": {
              "name": {
                "type": "string",
                "description": "Who publishes the data."
              },
              "url": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "license": {
                "type": "string",
                "description": "The terms the data comes under."
              }
            },
            "additionalProperties": false,
            "description": "Where the data comes from."
          },
          "documentCount": {
            "type": "integer",
            "description": "The documents that are ready to query. Updated each minute.",
            "title": "int"
          },
          "indexedBytes": {
            "type": "string",
            "description": "The bytes of the ready documents, as a decimal string. Updated each minute."
          },
          "indexedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the newest ready document finished indexing."
          },
          "examples": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["query", "mode"],
              "properties": {
                "query": {
                  "type": "string"
                },
                "mode": {
                  "type": "string",
                  "enum": ["hybrid", "keyword", "answer", "research"],
                  "description": "hybrid or keyword: Search objects. answer: Answer a question. research: Start research."
                }
              },
              "additionalProperties": false
            },
            "description": "Questions that show what the dataset answers. At most 6."
          },
          "access": {
            "type": "object",
            "required": ["price", "state"],
            "properties": {
              "price": {
                "anyOf": [
                  {
                    "type": "object",
                    "required": ["kind"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": ["free"]
                      }
                    },
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "required": ["kind", "monthlyUsd"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": ["paid"]
                      },
                      "monthlyUsd": {
                        "type": "integer",
                        "description": "The price a month, in whole US dollars.",
                        "title": "int"
                      }
                    },
                    "additionalProperties": false
                  }
                ]
              },
              "state": {
                "type": "string",
                "enum": ["open", "subscribed", "locked"],
                "description": "For the calling workspace. open: free. subscribed: paid, and the workspace has access. locked: paid, and a query returns 403 dataset_access_required."
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false,
        "description": "A read-only set of documents that Graphon curates. Every workspace can query a dataset by its id, with the same routes as a bucket. It holds no storage of the workspace.",
        "title": "Dataset",
        "examples": [
          {
            "id": "dstC4s3L4w0x1",
            "slug": "us-case-law",
            "title": "US case law",
            "summary": "Opinions of the US Supreme Court and the federal courts of appeals.",
            "description": "Every published opinion of the US Supreme Court since 1950, and of the federal courts of appeals since 2000, as plain text.",
            "category": "legal",
            "source": {
              "name": "CourtListener",
              "url": "https://www.courtlistener.com",
              "license": "Public domain"
            },
            "documentCount": 412904,
            "indexedBytes": "8392045113",
            "indexedAt": "2026-10-26T04:12:00.000Z",
            "examples": [
              {
                "query": "Which cases overruled Chevron?",
                "mode": "answer"
              }
            ],
            "access": {
              "price": {
                "kind": "free"
              },
              "state": "open"
            }
          }
        ]
      },
      "SearchRequest": {
        "type": "object",
        "required": ["target", "query"],
        "properties": {
          "target": {
            "type": "string",
            "description": "What to query: a bucket id (bkt…) of this workspace with indexing enabled, or a dataset id (dst…) from List datasets.",
            "examples": ["bktA1b2C3d4E5"],
            "pattern": "^(?:bkt|dst)[0-9A-Za-z]{10}$"
          },
          "query": {
            "type": "string",
            "description": "The text to search for. It must contain text. At most 32,000 characters.",
            "title": "maxLength(32000)",
            "maxLength": 32000,
            "pattern": "\\S"
          },
          "mode": {
            "type": "string",
            "enum": ["hybrid", "keyword"],
            "description": "hybrid: Use it for most searches. It matches exact words and meaning together. About a second. keyword: Use it for exact words, such as an ID, a code, or an error message. The quickest mode. Defaults to hybrid."
          },
          "resultType": {
            "type": "string",
            "enum": ["object", "passage"],
            "description": "The kind of result. object: one result per object, with up to 3 spans. passage: one span per result, so an object can appear more than once. Both have the same shape. Defaults to object."
          },
          "limit": {
            "type": "integer",
            "description": "Results on one page, 1 to 100. Defaults to 10.",
            "title": "between(1, 100)",
            "minimum": 1,
            "maximum": 100
          },
          "cursor": {
            "type": "string",
            "description": "nextCursor from the previous page. Send it with the same body. It works for 40 minutes."
          },
          "keys": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "a string at most 1024 character(s) long",
              "title": "maxLength(1024)",
              "minLength": 1,
              "maxLength": 1024
            },
            "description": "Use only these object keys. At most 50. With keyPrefix, an object must match both. Defaults to every object of the bucket.",
            "title": "maxItems(50)",
            "maxItems": 50
          },
          "keyPrefix": {
            "type": "string",
            "description": "Use only the objects whose key begins with this text, for example videos/2026/. Defaults to every object of the bucket.",
            "title": "maxLength(1024)",
            "minLength": 1,
            "maxLength": 1024
          },
          "filter": {
            "description": "Use only the objects whose metadata matches. A clause is { field, op, value } on a metadata field that the bucket lists. text takes every operator. number and time take eq, neq, gt, gte, lt, and lte. bool takes eq and neq. A value is text, a number or a decimal string, an RFC 3339 time, or true or false; in takes an array of 1 to 100 values. and, or, and not combine clauses, at most 4 levels deep and 32 clauses in all. neq and not keep objects that have no value for the field. With keys or keyPrefix, an object must match all of them. A field that is still indexing after a change fails with metadata_field_indexing.",
            "examples": [
              {
                "and": [
                  {
                    "field": "team",
                    "op": "eq",
                    "value": "search"
                  },
                  {
                    "field": "year",
                    "op": "gte",
                    "value": 2025
                  }
                ]
              }
            ],
            "anyOf": [
              {
                "type": "object",
                "required": ["field", "op", "value"],
                "properties": {
                  "field": {
                    "type": "string",
                    "minLength": 1
                  },
                  "op": {
                    "type": "string",
                    "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "prefix", "in"]
                  },
                  "value": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "boolean"
                      },
                      {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ]
                        }
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["and"],
                "properties": {
                  "and": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "description": "A nested filter of the same shape."
                    }
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["or"],
                "properties": {
                  "or": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "description": "A nested filter of the same shape."
                    }
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["not"],
                "properties": {
                  "not": {
                    "type": "object",
                    "description": "A nested filter of the same shape."
                  }
                },
                "additionalProperties": false
              }
            ]
          }
        },
        "additionalProperties": false,
        "description": "What to search for, and in which bucket or dataset.",
        "title": "SearchRequest",
        "examples": [
          {
            "target": "bktA1b2C3d4E5",
            "query": "checkout connection pool exhausted",
            "mode": "hybrid",
            "resultType": "object",
            "limit": 10
          }
        ]
      },
      "SearchResponse": {
        "type": "object",
        "required": [
          "results",
          "nextCursor",
          "execution",
          "indexGeneration",
          "timingMs",
          "warnings"
        ],
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchResult"
            },
            "description": "The best matches first."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The cursor of the next page. Null on the last page. One search reaches at most 200 passages."
          },
          "execution": {
            "type": "object",
            "required": ["mode"],
            "properties": {
              "mode": {
                "type": "string",
                "enum": ["hybrid", "keyword"],
                "description": "The mode that ran."
              }
            },
            "additionalProperties": false,
            "description": "How the search ran."
          },
          "indexGeneration": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Changes each time the index of the bucket or dataset changes. A cursor keeps the generation of its first page."
          },
          "timingMs": {
            "type": "object",
            "required": ["retrieval", "total"],
            "properties": {
              "retrieval": {
                "type": "integer",
                "description": "Milliseconds spent finding matches.",
                "title": "int"
              },
              "total": {
                "type": "integer",
                "description": "Milliseconds spent in total.",
                "title": "int"
              }
            },
            "additionalProperties": false,
            "description": "Milliseconds spent."
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchWarning"
            },
            "description": "index_empty: the bucket has no indexed objects. index_failed: every object failed to index. Either way there are no results."
          }
        },
        "additionalProperties": false,
        "description": "Ranked results. Read spans with Read spans, or the whole object from the storage API with its key and versionId.",
        "title": "SearchResponse",
        "examples": [
          {
            "results": [
              {
                "key": "incidents/2026-10-03-checkout.pdf",
                "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                "contentType": "application/pdf",
                "rank": 1,
                "score": 0.83,
                "spans": [
                  {
                    "key": "incidents/2026-10-03-checkout.pdf",
                    "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                    "unit": "chars",
                    "start": 18240,
                    "end": 19310,
                    "pages": {
                      "start": 4,
                      "end": 5
                    }
                  }
                ]
              }
            ],
            "nextCursor": "eyJ2IjoxLCJnIjoiZ2VuXzAxSkE3UTNWOEsifQ",
            "execution": {
              "mode": "hybrid"
            },
            "indexGeneration": "gen_01JA7Q3V8K2M4N6P8R0T2W4Y6Z",
            "timingMs": {
              "retrieval": 34,
              "total": 47
            },
            "warnings": []
          }
        ]
      },
      "SearchResult": {
        "type": "object",
        "required": ["key", "versionId", "contentType", "rank", "score", "spans"],
        "properties": {
          "key": {
            "type": "string",
            "description": "The object key."
          },
          "versionId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The object version that matched. It can be older than the current version while a newer one is indexing. Null when the version is gone."
          },
          "contentType": {
            "type": "string",
            "description": "The object's content type."
          },
          "rank": {
            "type": "integer",
            "description": "Rank 1 is the best match.",
            "title": "int"
          },
          "score": {
            "type": "number",
            "description": "Orders the results of this request only. It is not a confidence."
          },
          "spans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Span"
            },
            "description": "Where in the object it matched, best first: at most 3 for an object result, and 1 for a passage result. Empty when versionId is null."
          },
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Match"
            },
            "description": "Not returned yet. One match for each span, in the same order."
          },
          "object": {
            "type": "object",
            "required": ["contentType", "sizeBytes"],
            "properties": {
              "contentType": {
                "type": "string",
                "description": "The content type of the part."
              },
              "sizeBytes": {
                "type": "integer",
                "description": "The size of the part in bytes, before base64.",
                "title": "nonNegative",
                "minimum": 0
              },
              "data": {
                "type": "string",
                "description": "The bytes, as base64. Present when the part is inline."
              },
              "url": {
                "type": "string",
                "description": "A link to the bytes. Present when the part did not fit inline, or delivery is url."
              },
              "expiresAt": {
                "type": "string",
                "description": "When the url stops working, in UTC. Read the span again for a new one."
              },
              "page": {
                "type": "integer",
                "description": "Not returned yet. The page of a page screenshot, from 1.",
                "title": "positive",
                "exclusiveMinimum": 0
              },
              "seconds": {
                "type": "number",
                "description": "Not returned yet. The time of a video frame, in seconds from the start."
              }
            },
            "additionalProperties": false,
            "description": "Not returned yet. The whole object.",
            "title": "Part"
          }
        },
        "additionalProperties": false,
        "description": "One object, or one passage of it, and where it matched.",
        "title": "SearchResult"
      },
      "Span": {
        "type": "object",
        "required": ["key", "versionId", "unit"],
        "properties": {
          "key": {
            "type": "string",
            "description": "The object key."
          },
          "versionId": {
            "type": "string",
            "description": "The object version."
          },
          "unit": {
            "type": "string",
            "enum": ["pages", "chars", "seconds", "file"],
            "description": "pages: pages of a PDF or an office file, from 1, such as a section or a figure. Page 7 is start 7, end 8. chars: Unicode code points of the text of the object, from 0. seconds: whole seconds of a video or a recording, from 0. file: the whole object, such as an image, with no start or end."
          },
          "start": {
            "type": "integer",
            "description": "The first unit of the span. Absent when unit is file.",
            "title": "nonNegative",
            "minimum": 0
          },
          "end": {
            "type": "integer",
            "description": "The unit after the span. The span is start to end, without end itself. Absent when unit is file.",
            "title": "nonNegative",
            "minimum": 0
          },
          "pages": {
            "type": "object",
            "required": ["start", "end"],
            "properties": {
              "start": {
                "type": "integer",
                "description": "The first page, from 1.",
                "title": "positive",
                "exclusiveMinimum": 0
              },
              "end": {
                "type": "integer",
                "description": "The page after the last page.",
                "title": "positive",
                "exclusiveMinimum": 0
              }
            },
            "additionalProperties": false,
            "description": "The pages that a chars span of a PDF or an office file covers, so a client can show a page number. Absent on every other span. Send it back unchanged, or leave it out."
          },
          "bbox": {
            "$ref": "#/components/schemas/BBox"
          }
        },
        "additionalProperties": false,
        "description": "A place in one object version. It holds no content. Read it with Read spans: include text for its words, raw for the pages, the text, the image, or the clip, and object for the whole object.",
        "title": "Span"
      },
      "BBox": {
        "type": "object",
        "required": ["left", "top", "right", "bottom"],
        "properties": {
          "left": {
            "type": "number",
            "description": "The left edge.",
            "title": "between(0, 1)",
            "minimum": 0,
            "maximum": 1
          },
          "top": {
            "type": "number",
            "description": "The top edge.",
            "title": "between(0, 1)",
            "minimum": 0,
            "maximum": 1
          },
          "right": {
            "type": "number",
            "description": "The right edge.",
            "title": "between(0, 1)",
            "minimum": 0,
            "maximum": 1
          },
          "bottom": {
            "type": "number",
            "description": "The bottom edge.",
            "title": "between(0, 1)",
            "minimum": 0,
            "maximum": 1
          }
        },
        "additionalProperties": false,
        "description": "Not returned yet. The box of a figure on one page, as fractions of the page from its top-left corner.",
        "title": "BBox"
      },
      "Match": {
        "type": "object",
        "required": ["span"],
        "properties": {
          "span": {
            "$ref": "#/components/schemas/Span"
          },
          "highlight": {
            "$ref": "#/components/schemas/Highlight"
          },
          "text": {
            "type": "string"
          },
          "screenshots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Part"
            }
          },
          "raw": {
            "$ref": "#/components/schemas/Part"
          }
        },
        "additionalProperties": false,
        "description": "Not returned yet. One place inside a span: where a search matched, or the passage that supports a citation, with the parts that include asks for.",
        "title": "Match"
      },
      "Highlight": {
        "type": "object",
        "required": ["text", "matchRanges"],
        "properties": {
          "text": {
            "type": "string",
            "description": "About 300 characters around the match."
          },
          "matchRanges": {
            "type": "array",
            "items": {
              "type": "array",
              "minItems": 2,
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "items": false
            },
            "description": "The [start, end) code point ranges of the matched words in text."
          }
        },
        "additionalProperties": false,
        "description": "Not returned yet. The text around a match, and where the matched words are.",
        "title": "Highlight"
      },
      "Part": {
        "type": "object",
        "required": ["contentType", "sizeBytes"],
        "properties": {
          "contentType": {
            "type": "string",
            "description": "The content type of the part."
          },
          "sizeBytes": {
            "type": "integer",
            "description": "The size of the part in bytes, before base64.",
            "title": "nonNegative",
            "minimum": 0
          },
          "data": {
            "type": "string",
            "description": "The bytes, as base64. Present when the part is inline."
          },
          "url": {
            "type": "string",
            "description": "A link to the bytes. Present when the part did not fit inline, or delivery is url."
          },
          "expiresAt": {
            "type": "string",
            "description": "When the url stops working, in UTC. Read the span again for a new one."
          },
          "page": {
            "type": "integer",
            "description": "Not returned yet. The page of a page screenshot, from 1.",
            "title": "positive",
            "exclusiveMinimum": 0
          },
          "seconds": {
            "type": "number",
            "description": "Not returned yet. The time of a video frame, in seconds from the start."
          }
        },
        "additionalProperties": false,
        "description": "Binary content: data inline, or a url when it did not fit or delivery is url.",
        "title": "Part"
      },
      "SearchWarning": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "string",
            "description": "index_empty (the bucket or dataset has nothing indexed), index_failed (everything in it failed to index), or, in an MCP answer_question result only, sources_trimmed (the result was over the size limit, so it lists only the cited sources)."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation."
          }
        },
        "additionalProperties": false,
        "description": "Something the caller should know about the result.",
        "title": "SearchWarning"
      },
      "ReadSpansRequest": {
        "type": "object",
        "required": ["target", "spans"],
        "properties": {
          "target": {
            "type": "string",
            "description": "What to query: a bucket id (bkt…) of this workspace with indexing enabled, or a dataset id (dst…) from List datasets.",
            "examples": ["bktA1b2C3d4E5"],
            "pattern": "^(?:bkt|dst)[0-9A-Za-z]{10}$"
          },
          "spans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Span"
            },
            "description": "The spans to read, 1 to 50, unchanged, as Search objects, Answer a question, or a run returned them.",
            "title": "maxItems(50)",
            "minItems": 1,
            "maxItems": 50
          },
          "include": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReadInclude"
            },
            "description": "The parts to return for each span. Each fills the result field of the same name. Defaults to text.",
            "title": "minItems(1)",
            "minItems": 1
          },
          "delivery": {
            "$ref": "#/components/schemas/Delivery"
          }
        },
        "additionalProperties": false,
        "description": "The spans to read, their bucket or dataset, and the parts to return. A span past the end of the object is cut to the object.",
        "title": "ReadSpansRequest",
        "examples": [
          {
            "target": "bktA1b2C3d4E5",
            "spans": [
              {
                "key": "manuals/pump.pdf",
                "versionId": "ver_8a1d4c7e2b9f4e6a8c3d5b7f1e9a2c4d",
                "unit": "chars",
                "start": 1200,
                "end": 3400,
                "pages": {
                  "start": 3,
                  "end": 5
                }
              }
            ],
            "include": ["text"],
            "delivery": "inline"
          }
        ]
      },
      "ReadInclude": {
        "type": "string",
        "enum": ["text", "raw", "object"],
        "description": "A part to return. text: the extracted text: the text of a document, or the speech of a video or a recording, with its lines. raw: the span cut from the object in its own format: a PDF of the pages, the text of a text file or a mail, the image, or a clip. object: the whole object version.",
        "title": "ReadInclude"
      },
      "Delivery": {
        "type": "string",
        "enum": ["inline", "url"],
        "description": "inline: each binary part as base64 data, up to 20 MiB a call in span order, and a url past that. url: each binary part as a url.",
        "title": "Delivery"
      },
      "ReadSpansResponse": {
        "type": "object",
        "required": ["results", "next"],
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReadSpansResult"
            },
            "description": "One result for each span, in order."
          },
          "next": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ReadSpansNext"
              },
              {
                "type": "null"
              }
            ],
            "description": "The body of the next read, or null. Send it with target until next is null."
          }
        },
        "additionalProperties": false,
        "description": "The content of each span, in the parts that include names. One part stops at 50,000 characters of text, 500 pages, or 600 seconds. next is the body of the next read.",
        "title": "ReadSpansResponse",
        "examples": [
          {
            "results": [
              {
                "span": {
                  "key": "manuals/pump.pdf",
                  "versionId": "ver_8a1d4c7e2b9f4e6a8c3d5b7f1e9a2c4d",
                  "unit": "chars",
                  "start": 1200,
                  "end": 3400,
                  "pages": {
                    "start": 3,
                    "end": 5
                  }
                },
                "contentType": "application/pdf",
                "text": "## Seal check\n\nClose the inlet valve before you open the pump housing. Replace the seal when it shows cracks."
              }
            ],
            "next": null
          }
        ]
      },
      "ReadSpansResult": {
        "type": "object",
        "required": ["span"],
        "properties": {
          "span": {
            "$ref": "#/components/schemas/Span"
          },
          "contentType": {
            "type": "string",
            "description": "The object's content type."
          },
          "text": {
            "type": "string",
            "description": "The text of the span: the text of a document, or the words of the lines of a video or a recording, one line each."
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TranscriptLine"
            },
            "description": "The lines of speech in the span, in time order. A line that crosses the end of the part comes in the next part. Empty when nobody speaks."
          },
          "screenshots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Part"
            },
            "description": "Not returned yet."
          },
          "raw": {
            "$ref": "#/components/schemas/Part"
          },
          "object": {
            "$ref": "#/components/schemas/Part"
          },
          "error": {
            "$ref": "#/components/schemas/ReadSpanError"
          }
        },
        "additionalProperties": false,
        "description": "The content of one span: error, or contentType and the parts. Never both. span is the place that the parts show, in the unit of the content, which can differ from the unit you sent: the text of a pages span comes back as chars with pages. Every part shows the same place: with text, raw is cut to the span of the text. A part that the object has no form for, such as the text of an image, is left out. The span of a result with error is the span you sent.",
        "title": "ReadSpansResult"
      },
      "TranscriptLine": {
        "type": "object",
        "required": ["start", "end", "text"],
        "properties": {
          "start": {
            "type": "number",
            "description": "The start of the line, in seconds."
          },
          "end": {
            "type": "number",
            "description": "The end of the line, in seconds."
          },
          "text": {
            "type": "string",
            "description": "The words of the line."
          }
        },
        "additionalProperties": false,
        "description": "One line of speech. Times are in seconds. To get the clip of a line, read a seconds span from floor(start) to ceil(end).",
        "title": "TranscriptLine"
      },
      "ReadSpanError": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "string",
            "description": "not_found (no such version in the target), invalid_span (the span does not fit the object), or content_unavailable (the content is not stored or cannot be read)."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation."
          }
        },
        "additionalProperties": false,
        "description": "Why one span has no content. The other spans still read.",
        "title": "ReadSpanError"
      },
      "ReadSpansNext": {
        "type": "object",
        "required": ["spans", "include", "delivery"],
        "properties": {
          "spans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Span"
            }
          },
          "include": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReadInclude"
            }
          },
          "delivery": {
            "$ref": "#/components/schemas/Delivery"
          }
        },
        "additionalProperties": false,
        "description": "The body of the next read: the rest of each span that did not fit. Send it with target.",
        "title": "ReadSpansNext"
      },
      "MetadataFields": {
        "type": "object",
        "required": ["fields"],
        "properties": {
          "fields": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "type": "object",
              "required": ["type", "status", "invalidValues"],
              "properties": {
                "type": {
                  "type": "string",
                  "enum": ["text", "number", "time", "bool"],
                  "description": "How a filter reads the value. text: as text. number: a number or a decimal string. time: an RFC 3339 time. bool: true or false."
                },
                "status": {
                  "type": "string",
                  "enum": ["ready", "indexing"],
                  "description": "ready, or indexing while the index is rewritten after a change. A filter on an indexing field fails with metadata_field_indexing. The rewrite takes up to about 30 minutes for a bucket with objects."
                },
                "invalidValues": {
                  "type": "number",
                  "description": "Objects whose value does not fit the type. A filter never matches them on this field. A lower bound, counted from a sample."
                }
              },
              "additionalProperties": false
            },
            "description": "The metadata fields by key, in key order. Empty when the bucket lists none."
          }
        },
        "additionalProperties": false,
        "description": "The metadata fields of a bucket: the metadata keys that a filter can read.",
        "title": "MetadataFields",
        "examples": [
          {
            "fields": {
              "team": {
                "type": "text",
                "status": "ready",
                "invalidValues": 0
              },
              "year": {
                "type": "number",
                "status": "indexing",
                "invalidValues": 0
              }
            }
          }
        ]
      },
      "UpdateMetadataFieldsRequest": {
        "type": "object",
        "required": ["fields"],
        "properties": {
          "fields": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "anyOf": [
                {
                  "type": "object",
                  "required": ["type"],
                  "properties": {
                    "type": {
                      "type": "string",
                      "enum": ["text", "number", "time", "bool"],
                      "description": "How a filter reads the value. text: as text. number: a number or a decimal string. time: an RFC 3339 time. bool: true or false."
                    }
                  },
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "The fields to change, by metadata key. A key left out keeps its setting. null removes the field. At most 256 keys, and a bucket lists at most 256 fields. A new key is 1 to 128 lowercase letters, digits, periods, underscores, or hyphens."
          }
        },
        "additionalProperties": false,
        "description": "Changes to the metadata fields of a bucket.",
        "title": "UpdateMetadataFieldsRequest",
        "examples": [
          {
            "fields": {
              "year": {
                "type": "number"
              },
              "old_tag": null
            }
          }
        ]
      },
      "AnswerRequest": {
        "type": "object",
        "required": ["target", "query"],
        "properties": {
          "target": {
            "type": "string",
            "description": "What to query: a bucket id (bkt…) of this workspace with indexing enabled, or a dataset id (dst…) from List datasets.",
            "examples": ["bktA1b2C3d4E5"],
            "pattern": "^(?:bkt|dst)[0-9A-Za-z]{10}$"
          },
          "query": {
            "type": "string",
            "description": "The question to answer. It must contain text. At most 32,000 characters.",
            "title": "maxLength(32000)",
            "maxLength": 32000,
            "pattern": "\\S"
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["role", "content"],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": ["user", "assistant"],
                  "description": "Who said this turn."
                },
                "content": {
                  "type": "string",
                  "description": "The text of the turn. At most 32,000 characters.",
                  "title": "maxLength(32000)",
                  "maxLength": 32000
                }
              },
              "additionalProperties": false
            },
            "description": "Earlier turns, oldest first. At most 32. Defaults to none.",
            "title": "maxItems(32)",
            "maxItems": 32
          },
          "image": {
            "type": "object",
            "required": ["mediaType", "data"],
            "properties": {
              "mediaType": {
                "type": "string",
                "enum": ["image/png", "image/jpeg", "image/webp"],
                "description": "The image format."
              },
              "data": {
                "type": "string",
                "description": "The image as base64 with no data: prefix. It decodes to at most 4 MiB.",
                "pattern": "^[A-Za-z0-9+/]*={0,2}$"
              }
            },
            "additionalProperties": false,
            "description": "Premium. A picture to ask about: PNG, JPEG, or WebP, at most 4 MiB. It adds up to 45 seconds. Graphon keeps no copy.",
            "x-graphon-premium": true
          },
          "keys": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "a string at most 1024 character(s) long",
              "title": "maxLength(1024)",
              "minLength": 1,
              "maxLength": 1024
            },
            "description": "Use only these object keys. At most 50. With keyPrefix, an object must match both. Defaults to every object of the bucket.",
            "title": "maxItems(50)",
            "maxItems": 50
          },
          "keyPrefix": {
            "type": "string",
            "description": "Use only the objects whose key begins with this text, for example videos/2026/. Defaults to every object of the bucket.",
            "title": "maxLength(1024)",
            "minLength": 1,
            "maxLength": 1024
          },
          "filter": {
            "description": "Use only the objects whose metadata matches. A clause is { field, op, value } on a metadata field that the bucket lists. text takes every operator. number and time take eq, neq, gt, gte, lt, and lte. bool takes eq and neq. A value is text, a number or a decimal string, an RFC 3339 time, or true or false; in takes an array of 1 to 100 values. and, or, and not combine clauses, at most 4 levels deep and 32 clauses in all. neq and not keep objects that have no value for the field. With keys or keyPrefix, an object must match all of them. A field that is still indexing after a change fails with metadata_field_indexing.",
            "examples": [
              {
                "and": [
                  {
                    "field": "team",
                    "op": "eq",
                    "value": "search"
                  },
                  {
                    "field": "year",
                    "op": "gte",
                    "value": 2025
                  }
                ]
              }
            ],
            "anyOf": [
              {
                "type": "object",
                "required": ["field", "op", "value"],
                "properties": {
                  "field": {
                    "type": "string",
                    "minLength": 1
                  },
                  "op": {
                    "type": "string",
                    "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "prefix", "in"]
                  },
                  "value": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "boolean"
                      },
                      {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ]
                        }
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["and"],
                "properties": {
                  "and": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "description": "A nested filter of the same shape."
                    }
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["or"],
                "properties": {
                  "or": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "description": "A nested filter of the same shape."
                    }
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["not"],
                "properties": {
                  "not": {
                    "type": "object",
                    "description": "A nested filter of the same shape."
                  }
                },
                "additionalProperties": false
              }
            ]
          },
          "instructions": {
            "type": "string",
            "description": "How to write the answer, for example its length, tone, format, or language. They replace only the default style rules. They do not change the citations. At most 8,000 characters. A blank value is the same as none. Defaults to none.",
            "title": "maxLength(8000)",
            "maxLength": 8000
          },
          "sources": {
            "type": "string",
            "enum": ["all", "cited", "none"],
            "description": "all: cited sources first, in the order the answer cites them, then the sources it only retrieved. cited: only the sources that the answer cites. none: no sources, and no [[SRC:0001]] markers in the answer. Defaults to all."
          }
        },
        "additionalProperties": false,
        "description": "The question, and the bucket or dataset to answer it from. Usually seconds. The call returns an answer or an error within about 2 minutes.",
        "title": "AnswerRequest",
        "examples": [
          {
            "target": "bktA1b2C3d4E5",
            "query": "Why did checkout stall after the 3 October deploy?",
            "history": [],
            "sources": "all"
          }
        ]
      },
      "AnswerResponse": {
        "type": "object",
        "required": ["answer", "sources", "warnings", "imageDescription", "timingMs"],
        "properties": {
          "answer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The answer, with a [[SRC:0001]] marker for each citation, or no markers with sources none. Null when the bucket or dataset had nothing to answer from."
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Source"
            },
            "description": "The sources that sources selects, in order: cited sources first, in the order the answer cites them, then the sources it only retrieved. One source for each place that was used, so every marker in the answer names exactly one source."
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchWarning"
            },
            "description": "index_empty or index_failed when the bucket had nothing to answer from. Then answer is null."
          },
          "imageDescription": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the image showed. Null without an image. Send it in history on a follow-up, so the next question sees the image with no resend."
          },
          "timingMs": {
            "type": "object",
            "required": ["total"],
            "properties": {
              "total": {
                "type": "integer",
                "description": "Milliseconds spent in total.",
                "title": "int"
              }
            },
            "additionalProperties": false,
            "description": "Milliseconds spent."
          }
        },
        "additionalProperties": false,
        "description": "The answer and its sources.",
        "title": "AnswerResponse",
        "examples": [
          {
            "answer": "Release 4.18 raised checkout workers from 8 to 24 but left the database pool at 200 [[SRC:0001]].",
            "sources": [
              {
                "ref": "SRC:0001",
                "key": "incidents/2026-10-03-checkout.pdf",
                "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                "contentType": "application/pdf",
                "score": 0.86,
                "cited": true,
                "span": {
                  "key": "incidents/2026-10-03-checkout.pdf",
                  "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                  "unit": "pages",
                  "start": 2,
                  "end": 3
                }
              }
            ],
            "warnings": [],
            "imageDescription": null,
            "timingMs": {
              "total": 6412
            }
          }
        ]
      },
      "Source": {
        "type": "object",
        "required": ["ref", "key", "versionId", "contentType", "score", "cited", "span"],
        "properties": {
          "ref": {
            "type": "string",
            "description": "The marker in the answer without its brackets, for example SRC:0001."
          },
          "key": {
            "type": "string",
            "description": "The object key."
          },
          "versionId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The object version that was used. Null when the version is gone."
          },
          "contentType": {
            "type": "string",
            "description": "The object's content type."
          },
          "score": {
            "type": "number",
            "description": "Orders the sources of this answer only. It is not a confidence."
          },
          "cited": {
            "type": "boolean",
            "description": "True when the answer cites this source. False for a source it only retrieved."
          },
          "span": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Span"
              },
              {
                "type": "null"
              }
            ],
            "description": "The place in the object that was used. Null when versionId is null."
          },
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Match"
            },
            "description": "Not returned yet. On a cited source, one match: the passage that supports the answer."
          },
          "object": {
            "type": "object",
            "required": ["contentType", "sizeBytes"],
            "properties": {
              "contentType": {
                "type": "string",
                "description": "The content type of the part."
              },
              "sizeBytes": {
                "type": "integer",
                "description": "The size of the part in bytes, before base64.",
                "title": "nonNegative",
                "minimum": 0
              },
              "data": {
                "type": "string",
                "description": "The bytes, as base64. Present when the part is inline."
              },
              "url": {
                "type": "string",
                "description": "A link to the bytes. Present when the part did not fit inline, or delivery is url."
              },
              "expiresAt": {
                "type": "string",
                "description": "When the url stops working, in UTC. Read the span again for a new one."
              },
              "page": {
                "type": "integer",
                "description": "Not returned yet. The page of a page screenshot, from 1.",
                "title": "positive",
                "exclusiveMinimum": 0
              },
              "seconds": {
                "type": "number",
                "description": "Not returned yet. The time of a video frame, in seconds from the start."
              }
            },
            "additionalProperties": false,
            "description": "Not returned yet. The whole object.",
            "title": "Part"
          }
        },
        "additionalProperties": false,
        "description": "One source of an answer: an object and the place in it.",
        "title": "Source"
      },
      "StartResearchRequest": {
        "type": "object",
        "required": ["target", "query"],
        "properties": {
          "target": {
            "type": "string",
            "description": "What to query: a bucket id (bkt…) of this workspace with indexing enabled, or a dataset id (dst…) from List datasets.",
            "examples": ["bktA1b2C3d4E5"],
            "pattern": "^(?:bkt|dst)[0-9A-Za-z]{10}$"
          },
          "query": {
            "type": "string",
            "description": "The question to answer. It must contain text. At most 32,000 characters.",
            "title": "maxLength(32000)",
            "maxLength": 32000,
            "pattern": "\\S"
          },
          "stream": {
            "type": "boolean",
            "description": "false: 202 with the running run at once. true: 200 text/event-stream, the events of the run until it ends, as Run events sends them. Either way the Location header names the run. Defaults to false."
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["role", "content"],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": ["user", "assistant"],
                  "description": "Who said this turn."
                },
                "content": {
                  "type": "string",
                  "description": "The text of the turn. At most 32,000 characters.",
                  "title": "maxLength(32000)",
                  "maxLength": 32000
                }
              },
              "additionalProperties": false
            },
            "description": "Earlier turns, oldest first. At most 32. Stored with the run. Defaults to none.",
            "title": "maxItems(32)",
            "maxItems": 32
          },
          "image": {
            "type": "object",
            "required": ["mediaType", "data"],
            "properties": {
              "mediaType": {
                "type": "string",
                "enum": ["image/png", "image/jpeg", "image/webp"],
                "description": "The image format."
              },
              "data": {
                "type": "string",
                "description": "The image as base64 with no data: prefix. It decodes to at most 4 MiB.",
                "pattern": "^[A-Za-z0-9+/]*={0,2}$"
              }
            },
            "additionalProperties": false,
            "description": "Premium. A picture to ask about: PNG, JPEG, or WebP, at most 4 MiB. It adds up to 45 seconds. Graphon keeps no copy.",
            "x-graphon-premium": true
          },
          "keys": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "a string at most 1024 character(s) long",
              "title": "maxLength(1024)",
              "minLength": 1,
              "maxLength": 1024
            },
            "description": "Use only these object keys. At most 50. With keyPrefix, an object must match both. Defaults to every object of the bucket.",
            "title": "maxItems(50)",
            "maxItems": 50
          },
          "keyPrefix": {
            "type": "string",
            "description": "Use only the objects whose key begins with this text, for example videos/2026/. Defaults to every object of the bucket.",
            "title": "maxLength(1024)",
            "minLength": 1,
            "maxLength": 1024
          },
          "filter": {
            "description": "Use only the objects whose metadata matches. A clause is { field, op, value } on a metadata field that the bucket lists. text takes every operator. number and time take eq, neq, gt, gte, lt, and lte. bool takes eq and neq. A value is text, a number or a decimal string, an RFC 3339 time, or true or false; in takes an array of 1 to 100 values. and, or, and not combine clauses, at most 4 levels deep and 32 clauses in all. neq and not keep objects that have no value for the field. With keys or keyPrefix, an object must match all of them. A field that is still indexing after a change fails with metadata_field_indexing.",
            "examples": [
              {
                "and": [
                  {
                    "field": "team",
                    "op": "eq",
                    "value": "search"
                  },
                  {
                    "field": "year",
                    "op": "gte",
                    "value": 2025
                  }
                ]
              }
            ],
            "anyOf": [
              {
                "type": "object",
                "required": ["field", "op", "value"],
                "properties": {
                  "field": {
                    "type": "string",
                    "minLength": 1
                  },
                  "op": {
                    "type": "string",
                    "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "prefix", "in"]
                  },
                  "value": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "boolean"
                      },
                      {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ]
                        }
                      }
                    ]
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["and"],
                "properties": {
                  "and": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "description": "A nested filter of the same shape."
                    }
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["or"],
                "properties": {
                  "or": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "description": "A nested filter of the same shape."
                    }
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "object",
                "required": ["not"],
                "properties": {
                  "not": {
                    "type": "object",
                    "description": "A nested filter of the same shape."
                  }
                },
                "additionalProperties": false
              }
            ]
          },
          "instructions": {
            "type": "string",
            "description": "How to write the answer, for example its length, tone, format, or language. They replace only the default style rules. They do not change the citations. At most 8,000 characters. A blank value is the same as none. Defaults to none.",
            "title": "maxLength(8000)",
            "maxLength": 8000
          }
        },
        "additionalProperties": false,
        "description": "The question and the bucket or dataset to research.",
        "title": "StartResearchRequest",
        "examples": [
          {
            "target": "bktA1b2C3d4E5",
            "query": "Why did checkout stall after the 3 October deploy?",
            "stream": false,
            "history": []
          }
        ]
      },
      "QueryRun": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "target",
          "status",
          "query",
          "history",
          "keys",
          "keyPrefix",
          "filter",
          "answer",
          "sources",
          "sourcesNextCursor",
          "warnings",
          "error",
          "imageDescription",
          "createdBy",
          "createdAt",
          "completedAt",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The run id: rsc and 10 characters."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "target": {
            "type": "string",
            "description": "The bucket id or the dataset id that the run reads."
          },
          "status": {
            "type": "string",
            "enum": ["running", "succeeded", "failed"],
            "description": "running, then succeeded or failed. It never goes back to running."
          },
          "query": {
            "type": "string",
            "description": "The question."
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["role", "content"],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": ["user", "assistant"],
                  "description": "Who said this turn."
                },
                "content": {
                  "type": "string",
                  "description": "The text of the turn. At most 32,000 characters.",
                  "title": "maxLength(32000)",
                  "maxLength": 32000
                }
              },
              "additionalProperties": false
            },
            "description": "The earlier turns."
          },
          "keys": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The object keys the run used, or empty for the whole bucket."
          },
          "keyPrefix": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The key prefix the run used, or null for the whole bucket."
          },
          "filter": {
            "anyOf": [
              {
                "description": "Use only the objects whose metadata matches. A clause is { field, op, value } on a metadata field that the bucket lists. text takes every operator. number and time take eq, neq, gt, gte, lt, and lte. bool takes eq and neq. A value is text, a number or a decimal string, an RFC 3339 time, or true or false; in takes an array of 1 to 100 values. and, or, and not combine clauses, at most 4 levels deep and 32 clauses in all. neq and not keep objects that have no value for the field. With keys or keyPrefix, an object must match all of them. A field that is still indexing after a change fails with metadata_field_indexing.",
                "examples": [
                  {
                    "and": [
                      {
                        "field": "team",
                        "op": "eq",
                        "value": "search"
                      },
                      {
                        "field": "year",
                        "op": "gte",
                        "value": 2025
                      }
                    ]
                  }
                ],
                "anyOf": [
                  {
                    "type": "object",
                    "required": ["field", "op", "value"],
                    "properties": {
                      "field": {
                        "type": "string",
                        "minLength": 1
                      },
                      "op": {
                        "type": "string",
                        "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "prefix", "in"]
                      },
                      "value": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "boolean"
                          },
                          {
                            "type": "array",
                            "minItems": 1,
                            "maxItems": 100,
                            "items": {
                              "anyOf": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "number"
                                },
                                {
                                  "type": "boolean"
                                }
                              ]
                            }
                          }
                        ]
                      }
                    },
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "required": ["and"],
                    "properties": {
                      "and": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                          "type": "object",
                          "description": "A nested filter of the same shape."
                        }
                      }
                    },
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "required": ["or"],
                    "properties": {
                      "or": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                          "type": "object",
                          "description": "A nested filter of the same shape."
                        }
                      }
                    },
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "required": ["not"],
                    "properties": {
                      "not": {
                        "type": "object",
                        "description": "A nested filter of the same shape."
                      }
                    },
                    "additionalProperties": false
                  }
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The metadata filter the run used, or null for none."
          },
          "answer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The answer, with a [[SRC:0001]] marker for each citation, or no markers when Answer a question asked for sources none. Null unless succeeded, and null on a success with nothing to answer from."
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Source"
            },
            "description": "One page of the sources that sources selects, in order: cited sources first, in the order the answer cites them, then the sources it only retrieved. One source for each place that was used."
          },
          "sourcesNextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as sourceCursor, with the same sources and sourceLimit, to read the next page of sources. Null on the last page."
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchWarning"
            },
            "description": "index_empty: the bucket has no objects to answer from. index_failed: every object failed to index. Either way there is no answer."
          },
          "error": {
            "anyOf": [
              {
                "type": "object",
                "required": ["code", "message", "retryable"],
                "properties": {
                  "code": {
                    "type": "string",
                    "enum": ["temporarily_unavailable", "index_not_ready", "internal_error"],
                    "description": "temporarily_unavailable: the search service could not finish the run. index_not_ready: the ready objects were deleted while others still index. internal_error: a bug, not load."
                  },
                  "message": {
                    "type": "string",
                    "description": "Human-readable explanation."
                  },
                  "retryable": {
                    "type": "boolean",
                    "description": "True when starting the same run again can succeed."
                  }
                },
                "additionalProperties": false,
                "description": "Why the run failed."
              },
              {
                "type": "null"
              }
            ],
            "description": "Null unless failed. retryable true means: start the run again."
          },
          "imageDescription": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the image showed. Null without an image. Send it in history on a follow-up, so the next question sees the image with no resend."
          },
          "createdBy": {
            "type": "object",
            "required": ["userId", "apiKeyId"],
            "properties": {
              "userId": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The user who started it, or null for a workspace key."
              },
              "apiKeyId": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The API key that started it, or null."
              }
            },
            "additionalProperties": false,
            "description": "The credential that started the run."
          },
          "createdAt": {
            "type": "string",
            "description": "When the run started, in UTC."
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the run ended, in UTC. Null while running."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the run ended, in UTC. Null while running."
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the run stops being readable, in UTC: seven days past completedAt. After it, Get research is 404. Null while running."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the run stops being readable, in UTC: seven days past completedAt. After it, Get research is 404. Null while running."
          }
        },
        "additionalProperties": false,
        "description": "A query run: a question that the search service answers on its own.",
        "title": "QueryRun",
        "examples": [
          {
            "id": "rscR7tY2kL9mP",
            "workspaceId": "wsp4k9m2x7q1z8r",
            "target": "bktA1b2C3d4E5",
            "status": "succeeded",
            "query": "Why did checkout stall after the 3 October deploy?",
            "history": [],
            "keys": [],
            "keyPrefix": null,
            "filter": null,
            "answer": "Release 4.18 raised checkout workers from 8 to 24 but left the database pool at 200 [[SRC:0001]].",
            "sources": [
              {
                "ref": "SRC:0001",
                "key": "incidents/2026-10-03-checkout.pdf",
                "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                "contentType": "application/pdf",
                "score": 0.86,
                "cited": true,
                "span": {
                  "key": "incidents/2026-10-03-checkout.pdf",
                  "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                  "unit": "pages",
                  "start": 2,
                  "end": 3
                }
              }
            ],
            "sourcesNextCursor": null,
            "warnings": [],
            "error": null,
            "imageDescription": null,
            "createdBy": {
              "userId": null,
              "apiKeyId": "apkH3sK8pW2xQ"
            },
            "createdAt": "2026-10-12T09:00:00.000Z",
            "completedAt": "2026-10-12T09:03:42.210Z",
            "expiresAt": "2026-10-19T09:03:42.210Z"
          }
        ]
      },
      "ResearchEnvelope": {
        "type": "object",
        "required": ["research"],
        "properties": {
          "research": {
            "$ref": "#/components/schemas/QueryRun"
          }
        },
        "additionalProperties": false,
        "description": "One query run.",
        "title": "ResearchEnvelope",
        "examples": [
          {
            "research": {
              "id": "rscR7tY2kL9mP",
              "workspaceId": "wsp4k9m2x7q1z8r",
              "target": "bktA1b2C3d4E5",
              "status": "succeeded",
              "query": "Why did checkout stall after the 3 October deploy?",
              "history": [],
              "keys": [],
              "keyPrefix": null,
              "filter": null,
              "answer": "Release 4.18 raised checkout workers from 8 to 24 but left the database pool at 200 [[SRC:0001]].",
              "sources": [
                {
                  "ref": "SRC:0001",
                  "key": "incidents/2026-10-03-checkout.pdf",
                  "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                  "contentType": "application/pdf",
                  "score": 0.86,
                  "cited": true,
                  "span": {
                    "key": "incidents/2026-10-03-checkout.pdf",
                    "versionId": "ver_3f9c2a7d1e4b4c8a9f0d6b2e5a1c7d3f",
                    "unit": "pages",
                    "start": 2,
                    "end": 3
                  }
                }
              ],
              "sourcesNextCursor": null,
              "warnings": [],
              "error": null,
              "imageDescription": null,
              "createdBy": {
                "userId": null,
                "apiKeyId": "apkH3sK8pW2xQ"
              },
              "createdAt": "2026-10-12T09:00:00.000Z",
              "completedAt": "2026-10-12T09:03:42.210Z",
              "expiresAt": "2026-10-19T09:03:42.210Z"
            }
          }
        ]
      },
      "WebhookList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookView"
            },
            "description": "The webhooks the caller can see, newest first."
          }
        },
        "additionalProperties": false,
        "description": "A list of webhooks.",
        "title": "WebhookList",
        "examples": [
          {
            "items": [
              {
                "id": "whkN4vB7qX2mZ",
                "workspaceId": "wspq7ws2np5l8z4",
                "name": "indexing-callbacks",
                "url": "https://hooks.example.com/graphon",
                "eventTypes": ["object.indexed", "object.indexing_failed"],
                "bucketIds": null,
                "enabled": true,
                "disabledReason": null,
                "ownerKind": "user",
                "ownerUserId": "usrB2c3D4e5F6",
                "signing": {
                  "secretFingerprint": "sha256:9b2d44f0",
                  "previousSecretFingerprint": null,
                  "previousSecretExpiresAt": null
                },
                "delivery": {
                  "pendingDeliveries": 0,
                  "lastSucceededAt": "2026-10-14T09:05:13.004Z",
                  "lastFailedAt": null
                },
                "createdBy": {
                  "userId": "usrB2c3D4e5F6",
                  "apiKeyId": null
                },
                "createdAt": "2026-10-14T09:00:00.000Z",
                "updatedAt": "2026-10-14T09:00:00.000Z"
              }
            ]
          }
        ]
      },
      "WebhookView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "url",
          "eventTypes",
          "bucketIds",
          "enabled",
          "disabledReason",
          "ownerKind",
          "ownerUserId",
          "signing",
          "delivery",
          "createdBy",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The webhook id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "url": {
            "type": "string",
            "description": "The receiver URL."
          },
          "eventTypes": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/WebhookEventType"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "The event types the webhook gets. Null means every type, also types added later."
          },
          "bucketIds": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "The buckets whose events the webhook gets. Null means every bucket, also buckets created later."
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether Graphon sends events to it."
          },
          "disabledReason": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["requested", "failing"]
              },
              {
                "type": "null"
              }
            ],
            "description": "requested: its owner or an Admin turned it off. failing: Graphon turned it off after 72 hours with no 2xx answer, or a 410 answer."
          },
          "ownerKind": {
            "type": "string",
            "enum": ["user", "workspace"],
            "description": "user for a personal webhook. workspace for a workspace webhook."
          },
          "ownerUserId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The member who owns a personal webhook. Null for a workspace webhook."
          },
          "signing": {
            "type": "object",
            "required": [
              "secretFingerprint",
              "previousSecretFingerprint",
              "previousSecretExpiresAt"
            ],
            "properties": {
              "secretFingerprint": {
                "type": "string",
                "description": "Identifies the current secret: sha256: and 8 hex characters."
              },
              "previousSecretFingerprint": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Identifies the previous secret while it still signs, else null."
              },
              "previousSecretExpiresAt": {
                "anyOf": [
                  {
                    "type": "string",
                    "description": "When the previous secret stops signing, or null."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When the previous secret stops signing, or null."
              }
            },
            "additionalProperties": false,
            "description": "The secrets that sign each POST. Never the secrets."
          },
          "delivery": {
            "type": "object",
            "required": ["pendingDeliveries", "lastSucceededAt", "lastFailedAt"],
            "properties": {
              "pendingDeliveries": {
                "type": "number",
                "description": "Deliveries queued or waiting for a retry."
              },
              "lastSucceededAt": {
                "anyOf": [
                  {
                    "type": "string",
                    "description": "When a delivery last succeeded, or null."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When a delivery last succeeded, or null."
              },
              "lastFailedAt": {
                "anyOf": [
                  {
                    "type": "string",
                    "description": "When a delivery last ended failed, or null."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When a delivery last ended failed, or null."
              }
            },
            "additionalProperties": false,
            "description": "A summary of the delivery log."
          },
          "createdBy": {
            "type": "object",
            "required": ["userId", "apiKeyId"],
            "properties": {
              "userId": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "apiKeyId": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "additionalProperties": false,
            "description": "The member or API key that created the webhook."
          },
          "createdAt": {
            "type": "string",
            "description": "When the webhook was created, in UTC."
          },
          "updatedAt": {
            "type": "string",
            "description": "When the webhook last changed, in UTC."
          }
        },
        "additionalProperties": false,
        "description": "One webhook. The signing secret is never included.",
        "title": "WebhookView",
        "examples": [
          {
            "id": "whkN4vB7qX2mZ",
            "workspaceId": "wspq7ws2np5l8z4",
            "name": "indexing-callbacks",
            "url": "https://hooks.example.com/graphon",
            "eventTypes": ["object.indexed", "object.indexing_failed"],
            "bucketIds": null,
            "enabled": true,
            "disabledReason": null,
            "ownerKind": "user",
            "ownerUserId": "usrB2c3D4e5F6",
            "signing": {
              "secretFingerprint": "sha256:9b2d44f0",
              "previousSecretFingerprint": null,
              "previousSecretExpiresAt": null
            },
            "delivery": {
              "pendingDeliveries": 0,
              "lastSucceededAt": "2026-10-14T09:05:13.004Z",
              "lastFailedAt": null
            },
            "createdBy": {
              "userId": "usrB2c3D4e5F6",
              "apiKeyId": null
            },
            "createdAt": "2026-10-14T09:00:00.000Z",
            "updatedAt": "2026-10-14T09:00:00.000Z"
          }
        ]
      },
      "WebhookEventType": {
        "type": "string",
        "enum": ["object.indexed", "object.indexing_failed"],
        "description": "object.indexed: an object version became searchable. object.indexing_failed: an object version could not be indexed.",
        "title": "WebhookEventType"
      },
      "CreateWebhookRequest": {
        "type": "object",
        "required": ["name", "url"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name, 1 to 100 characters."
          },
          "url": {
            "type": "string",
            "description": "The receiver. HTTPS, no user name or password, no fragment, and a public address."
          },
          "eventTypes": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Event types to send. Leave out or send null for every type."
          },
          "bucketIds": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Buckets whose events to send. Leave out or send null for every bucket."
          },
          "enabled": {
            "type": "boolean",
            "description": "Default true."
          },
          "owner": {
            "type": "string",
            "enum": ["me", "workspace"],
            "description": "Defaults to me for a member and to workspace for a workspace key. Only an Admin can make a workspace webhook as a member.",
            "title": "WebhookOwner"
          }
        },
        "additionalProperties": false,
        "description": "Create payload for a webhook.",
        "title": "CreateWebhookRequest",
        "examples": [
          {
            "name": "indexing-callbacks",
            "url": "https://hooks.example.com/graphon",
            "eventTypes": ["object.indexed", "object.indexing_failed"]
          }
        ]
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "url": {
            "type": "string",
            "description": "The receiver URL."
          },
          "eventTypes": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Event types to send, or null for every type."
          },
          "bucketIds": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Buckets whose events to send, or null for every bucket."
          },
          "enabled": {
            "type": "boolean",
            "description": "false turns the webhook off and ends its pending deliveries. true turns it on for later events."
          }
        },
        "additionalProperties": false,
        "description": "Send at least one field.",
        "title": "UpdateWebhookRequest",
        "examples": [
          {
            "url": "https://hooks.example.com/v2/graphon",
            "eventTypes": null
          }
        ]
      },
      "RotateWebhookSecretRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "previousSecretExpiresInSeconds": {
            "type": "number",
            "description": "How long the previous secret keeps signing: 0 to 604800 (7 days). Default 86400. 0 stops it at once."
          }
        },
        "additionalProperties": false,
        "description": "Rotate payload. The body is optional.",
        "title": "RotateWebhookSecretRequest",
        "examples": [
          {
            "previousSecretExpiresInSeconds": 86400
          }
        ]
      },
      "CreatedWebhook": {
        "type": "object",
        "required": ["webhook", "secret"],
        "properties": {
          "webhook": {
            "$ref": "#/components/schemas/WebhookView"
          },
          "secret": {
            "type": "string",
            "description": "The signing secret, whsec_ and base64. Shown once. Check each POST with a Standard Webhooks library."
          }
        },
        "additionalProperties": false,
        "description": "Store the secret now. It is not shown again.",
        "title": "CreatedWebhook",
        "examples": [
          {
            "webhook": {
              "id": "whkN4vB7qX2mZ",
              "workspaceId": "wspq7ws2np5l8z4",
              "name": "indexing-callbacks",
              "url": "https://hooks.example.com/graphon",
              "eventTypes": ["object.indexed", "object.indexing_failed"],
              "bucketIds": null,
              "enabled": true,
              "disabledReason": null,
              "ownerKind": "user",
              "ownerUserId": "usrB2c3D4e5F6",
              "signing": {
                "secretFingerprint": "sha256:9b2d44f0",
                "previousSecretFingerprint": null,
                "previousSecretExpiresAt": null
              },
              "delivery": {
                "pendingDeliveries": 0,
                "lastSucceededAt": "2026-10-14T09:05:13.004Z",
                "lastFailedAt": null
              },
              "createdBy": {
                "userId": "usrB2c3D4e5F6",
                "apiKeyId": null
              },
              "createdAt": "2026-10-14T09:00:00.000Z",
              "updatedAt": "2026-10-14T09:00:00.000Z"
            },
            "secret": "whsec_<shown once>"
          }
        ]
      },
      "WebhookTestResult": {
        "type": "object",
        "required": ["attempt"],
        "properties": {
          "attempt": {
            "type": "object",
            "required": ["status", "responseStatus", "error", "durationMs", "sentAt"],
            "properties": {
              "status": {
                "type": "string",
                "enum": ["succeeded", "retry", "failed"],
                "description": "succeeded: a 2xx answer. retry: another attempt follows. failed: no more attempts."
              },
              "responseStatus": {
                "anyOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The HTTP status of the answer, or null when there was none."
              },
              "error": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Null when the receiver answered. Else timeout, dns_failed, address_not_public, connection_failed, tls_failed, redirect_not_followed, or interrupted."
              },
              "durationMs": {
                "type": "number",
                "description": "How long the POST took."
              },
              "sentAt": {
                "type": "string",
                "description": "When the POST was sent, in UTC."
              }
            },
            "additionalProperties": false,
            "description": "The test POST and the answer. A failed receiver still returns 200 here."
          }
        },
        "additionalProperties": false,
        "description": "The result of one webhook.test POST.",
        "title": "WebhookTestResult",
        "examples": [
          {
            "attempt": {
              "status": "succeeded",
              "responseStatus": 204,
              "error": null,
              "durationMs": 87,
              "sentAt": "2026-10-14T09:01:00.112Z"
            }
          }
        ]
      },
      "WebhookDeliveryList": {
        "type": "object",
        "required": ["items", "nextCursor"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "eventId",
                "eventType",
                "timestamp",
                "status",
                "attemptCount",
                "nextAttemptAt",
                "lastAttempt",
                "queuedAt"
              ],
              "properties": {
                "eventId": {
                  "type": "string",
                  "description": "The event id, the webhook-id header."
                },
                "eventType": {
                  "type": "string",
                  "description": "The event type."
                },
                "timestamp": {
                  "type": "string",
                  "description": "When the event happened, in UTC."
                },
                "status": {
                  "type": "string",
                  "enum": ["pending", "succeeded", "failed"],
                  "description": "pending: queued or waiting for a retry. succeeded: a 2xx answer. failed: no 2xx after the last attempt, or the webhook turned off."
                },
                "attemptCount": {
                  "type": "number",
                  "description": "Attempts in this round. A replay starts a new round."
                },
                "nextAttemptAt": {
                  "anyOf": [
                    {
                      "type": "string",
                      "description": "When the next attempt goes, or null."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When the next attempt goes, or null."
                },
                "lastAttempt": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/WebhookAttemptView"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The newest POST, or null before the first."
                },
                "queuedAt": {
                  "type": "string",
                  "description": "When the event was queued for this webhook, or queued again by a replay."
                }
              },
              "additionalProperties": false
            },
            "description": "The delivery log, newest first."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send as cursor for the next page. Null on the last page."
          }
        },
        "additionalProperties": false,
        "description": "A page of the delivery log.",
        "title": "WebhookDeliveryList",
        "examples": [
          {
            "items": [
              {
                "eventId": "evtW2nC6vJ0hS",
                "eventType": "object.indexed",
                "timestamp": "2026-10-14T09:05:12.481Z",
                "status": "succeeded",
                "attemptCount": 1,
                "nextAttemptAt": null,
                "lastAttempt": {
                  "number": 1,
                  "status": "succeeded",
                  "responseStatus": 204,
                  "error": null,
                  "durationMs": 64,
                  "sentAt": "2026-10-14T09:05:13.004Z"
                },
                "queuedAt": "2026-10-14T09:05:12.533Z"
              }
            ],
            "nextCursor": null
          }
        ]
      },
      "WebhookAttemptView": {
        "type": "object",
        "required": ["number", "status", "responseStatus", "error", "durationMs", "sentAt"],
        "properties": {
          "number": {
            "type": "number",
            "description": "The attempt number in its round, from 1."
          },
          "status": {
            "type": "string",
            "enum": ["succeeded", "retry", "failed"],
            "description": "succeeded: a 2xx answer. retry: another attempt follows. failed: no more attempts."
          },
          "responseStatus": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The HTTP status of the answer, or null when there was none."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Null when the receiver answered. Else timeout, dns_failed, address_not_public, connection_failed, tls_failed, redirect_not_followed, or interrupted."
          },
          "durationMs": {
            "type": "number",
            "description": "How long the POST took."
          },
          "sentAt": {
            "type": "string",
            "description": "When the POST was sent, in UTC."
          }
        },
        "additionalProperties": false,
        "description": "One POST.",
        "title": "WebhookAttemptView"
      },
      "WebhookDeliveryDetail": {
        "type": "object",
        "required": [
          "eventId",
          "eventType",
          "timestamp",
          "status",
          "attemptCount",
          "nextAttemptAt",
          "lastAttempt",
          "queuedAt",
          "body",
          "attempts"
        ],
        "properties": {
          "eventId": {
            "type": "string",
            "description": "The event id, the webhook-id header."
          },
          "eventType": {
            "type": "string",
            "description": "The event type."
          },
          "timestamp": {
            "type": "string",
            "description": "When the event happened, in UTC."
          },
          "status": {
            "type": "string",
            "enum": ["pending", "succeeded", "failed"],
            "description": "pending: queued or waiting for a retry. succeeded: a 2xx answer. failed: no 2xx after the last attempt, or the webhook turned off."
          },
          "attemptCount": {
            "type": "number",
            "description": "Attempts in this round. A replay starts a new round."
          },
          "nextAttemptAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the next attempt goes, or null."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the next attempt goes, or null."
          },
          "lastAttempt": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WebhookAttemptView"
              },
              {
                "type": "null"
              }
            ],
            "description": "The newest POST, or null before the first."
          },
          "queuedAt": {
            "type": "string",
            "description": "When the event was queued for this webhook, or queued again by a replay."
          },
          "body": {
            "type": "object",
            "required": [],
            "properties": {},
            "additionalProperties": {
              "$id": "/schemas/unknown",
              "title": "unknown"
            },
            "description": "The exact JSON that Graphon sends."
          },
          "attempts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookAttemptView"
            },
            "description": "Every POST of the event, oldest first, replays included."
          }
        },
        "additionalProperties": false,
        "description": "One event at one webhook, with its body and every attempt.",
        "title": "WebhookDeliveryDetail"
      },
      "ReplayWebhookDeliveriesRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "eventIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Event ids to send again."
          },
          "since": {
            "type": "string",
            "description": "Send again the events that happened at or after this time."
          },
          "until": {
            "type": "string",
            "description": "Only with since. Events before this time. Default now."
          },
          "onlyFailed": {
            "type": "boolean",
            "description": "Only deliveries that ended failed. Default false."
          }
        },
        "additionalProperties": false,
        "description": "Send eventIds or since.",
        "title": "ReplayWebhookDeliveriesRequest",
        "examples": [
          {
            "since": "2026-10-13T00:00:00Z",
            "onlyFailed": true
          }
        ]
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "Send Authorization: Bearer gak_{accessKeyId}.{secret}, or an OAuth access token for this API, such as the one graphon login gets. A key belongs to one workspace. Its role is viewer, editor, or admin.",
        "type": "http",
        "scheme": "bearer"
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The signed-in CLI user, or the API key that sent the request."
    },
    {
      "name": "Workspaces",
      "description": "Workspace read and administration."
    },
    {
      "name": "Members",
      "description": "Workspace membership and member API keys."
    },
    {
      "name": "Invitations",
      "description": "Pending workspace invitations."
    },
    {
      "name": "API keys",
      "description": "Personal and workspace API keys."
    },
    {
      "name": "Datasets",
      "description": "The catalog of datasets that Graphon curates. Query a dataset with Search objects, Answer a question, or Start research, with its id as target."
    },
    {
      "name": "Search",
      "description": "Find the objects of a bucket, or the documents of a dataset, that match a text."
    },
    {
      "name": "Metadata fields",
      "description": "The metadata keys of a bucket that a search, an answer, or a research run can filter on."
    },
    {
      "name": "Answer",
      "description": "Answer a question from a bucket or a dataset."
    },
    {
      "name": "Research",
      "description": "Research one bucket or dataset in depth, and follow the run as it works."
    },
    {
      "name": "Webhooks",
      "description": "Receivers that Graphon calls when something happens in a workspace. Each POST is signed with the Standard Webhooks scheme."
    }
  ],
  "servers": [
    {
      "url": "https://api.beta.graphon.ai"
    }
  ]
}
