{
  "openapi": "3.1.0",
  "info": {
    "title": "MooverApp Tenant API",
    "version": "v1",
    "description": "Everything a site is made of, as an API: accounts and projects, websites and the domains they answer on, pages, blocks, menus, blog, media, themes, views and settings. This is the surface the MooverApp admin itself is written against \u2014 there is no capability behind it that the UI has and a client does not.\n\nThe semantics are AIP over plain REST/JSON: five standard methods on named resources, `snake_case` bodies, `page_size`/`page_token`/`order_by`/`filter` on every list, `google.rpc.Status` errors, `etag` + `If-Match` for concurrency, and an Operation to poll whenever the work outlives the call. Authenticate with `POST /tenant-api/v1/users:authenticate` and send the JWT as `Authorization: Bearer <token>`."
  },
  "servers": [
    {
      "url": "https://tenant-api.mvrapp.io",
      "description": "Production."
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The account a tenant signs in to. It owns the projects, and every website hangs off one of them."
    },
    {
      "name": "Project",
      "description": "A grouping of websites inside one account \u2014 the parent a website is created under."
    },
    {
      "name": "Website",
      "description": "The unit the platform publishes. Creating one starts provisioning and answers with an Operation to poll (\u00a717); `code` is immutable because the platform hostname is built from it."
    },
    {
      "name": "Custom Domain",
      "description": "A read-only projection of where a website answers: platform hostname, connection status, and the record `:verify` checks. The domain itself is written through the `general.web.custom_domain` setting."
    },
    {
      "name": "CMS Page",
      "description": "Pages of the site \u2014 title, `url_key`, rich-text content and SEO metadata. An empty `visible_view_ids` means every view, not none."
    },
    {
      "name": "CMS Page View",
      "description": "The per-view overlay of one page: what that view says instead of the master. A field counts as overridden only while its name is in `overridden`."
    },
    {
      "name": "CMS Page Group",
      "description": "The versions of one page for customer groups: what a signed-in customer of the group reads instead of the page \u2014 a price, a condition, a hero. The group with the highest `priority` wins; everybody else reads the page."
    },
    {
      "name": "CMS Block",
      "description": "Reusable fragments of content, addressed by `identifier` and pulled into pages, themes and smart links."
    },
    {
      "name": "CMS Block View",
      "description": "The per-view overlay of one block: its content in that view."
    },
    {
      "name": "Navigation",
      "description": "Menus and their items \u2014 nesting and order through `:move`, plus the per-view overlay of a single item\u2019s title, URL and visibility."
    },
    {
      "name": "Email Template",
      "description": "The subject and text of the emails a website sends \u2014 the contact form\u2019s notification today \u2014 as plain text with `{{placeholders}}`, plus the per-view overlay that says it in another view\u2019s language. The platform creates the default template of each kind; it can be edited, not deleted."
    },
    {
      "name": "Blog",
      "description": "Posts, categories, tags and authors, each with a per-view overlay of its own. Categories form a tree reordered with `:move`, and `:set_posts` replaces the posts of one category in a single call."
    },
    {
      "name": "Editorial",
      "description": "The publication rules of one website, the backlog of what it means to write about, and the rolling calendar that turns the two into dated drafts. `editorial_plan` is a singleton that always exists, `:refill` fills the calendar on demand, and a slot becomes a post with `:materialize` and goes live with `:publish`."
    },
    {
      "name": "Editorial AI",
      "description": "The desk writing its own drafts: the policy that names which of the account\u2019s AI agents write, review and translate, and the generation \u2014 one run of the pipeline for one slot, with its steps, the AI executions behind them, a verdict and a cost. A run never overwrites a field a person edited, and publishes nothing its verdict did not pass."
    },
    {
      "name": "Customer",
      "description": "The visitors who have an account on a website, and the groups they are segmented into \u2014 by hand in a `MANUAL` group, by a rule in a `DYNAMIC` one. A customer belongs to one website, and signs in to it on the site itself; what is managed here is who they are, which groups they are in, and whether they may sign in at all. The fields a website adds to its customers \u2014 `customer_attributes`, in sections of `customer_attribute_groups` \u2014 are defined here too, and put in order with `:move`."
    },
    {
      "name": "AI",
      "description": "How an account runs AI work: the connection that pays for it (its own Anthropic key, or the platform\u2019s), the agent that says by which rules to run, the versioned instruction it renders, and the execution \u2014 one persistent run, with its model, its attempts, its tokens and its output. `ai_models` and `ai_system_agents` are the platform\u2019s own read-only catalogues to build on."
    },
    {
      "name": "AI Billing",
      "description": "What an account\u2019s AI work cost: the balance and the limits it is spent against, the immutable ledger of every charge, and the usage record of every attempt \u2014 kept for a key of your own too, where nothing is charged."
    },
    {
      "name": "Media",
      "description": "The image library: multipart upload, folders, and the read that serves a stored file transformed on the fly \u2014 `w`, `h`, `crop`, `q` and `fmt` are the whole vocabulary, and it is the same URL a rendered site fetches."
    },
    {
      "name": "Analytics",
      "description": "What a website\u2019s visitors did, as metrics rather than as events: requests, page views, unique visitors and who is on the site right now. `:query` reads one metric over a period in the site\u2019s own time zone, as a total and as a series; anything counted with a probabilistic sketch says so with `approximate`. Collection happens on the site\u2019s own domain and is not part of this API."
    },
    {
      "name": "Dashboard",
      "description": "The widget grid a tenant arranges for one website \u2014 what is on it, where, and how each tile is configured \u2014 plus `dashboard_widget_types`, the platform\u2019s catalogue of tiles it can hold. The dashboard is a singleton that always exists: read it before anything was ever saved and it answers with the default layout, and `:reset` puts that layout back."
    },
    {
      "name": "View",
      "description": "A view is one presentation of a website \u2014 its locale, its URL prefix and its fallback. Content carries a per-view overlay, and settings can be overridden per view."
    },
    {
      "name": "View Settings",
      "description": "Settings overridden for one view, addressed by their dotted path, plus `setting_descriptors` \u2014 the registry of paths that may be overridden at all."
    },
    {
      "name": "Website Settings",
      "description": "Website-wide settings, addressed by their dotted path. `:batch_update` writes many of them atomically."
    },
    {
      "name": "Theme",
      "description": "The CSS-variable map a site renders with, plus the branding and wiring around it: logo, favicon, main menu and footer block. An unknown variable survives a round trip."
    },
    {
      "name": "Operation",
      "description": "The long-running operation of \u00a717: poll until `done`, then read exactly one of `response` / `error`. `:cancel` asks a running one to stop."
    },
    {
      "name": "Search",
      "description": "Re-indexing a website\u2019s search corpus. It answers with an Operation; there is no query endpoint here \u2014 ranked search is served on the site\u2019s own domain."
    },
    {
      "name": "User",
      "description": "Sign-in and the password lifecycle. `:authenticate` returns the bearer JWT every other call needs."
    },
    {
      "name": "User Profile",
      "description": "The signed-in user\u2019s own profile \u2014 read it, patch it, or close the account with `:delete_account`."
    },
    {
      "name": "Access",
      "description": "Who belongs to an account and what each member may do. `permissions` is the tree of sections a right is granted on \u2014 `READ` or `WRITE`, and a grant covers everything under its section \u2014 `roles` the three every account has: administrator, editor, and one that holds only the sections its membership grants, `accounts/{account}/roles` the named sets of grants an account defines for itself, `accounts/{account}/members` the account\u2019s members with their roles, and `accounts/{account}/invitations` the people asked to join by e-mail \u2014 who take the mailed link up with `invitations:accept`. A route a member\u2019s role does not reach answers PERMISSION_DENIED."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Websites & provisioning",
      "tags": [
        "Account",
        "Project",
        "Website",
        "Custom Domain"
      ]
    },
    {
      "name": "Content",
      "tags": [
        "CMS Page",
        "CMS Page View",
        "CMS Page Group",
        "CMS Block",
        "CMS Block View",
        "Navigation",
        "Email Template"
      ]
    },
    {
      "name": "Blog",
      "tags": [
        "Blog"
      ]
    },
    {
      "name": "Editorial desk",
      "tags": [
        "Editorial",
        "Editorial AI"
      ]
    },
    {
      "name": "Customers",
      "tags": [
        "Customer"
      ]
    },
    {
      "name": "AI platform",
      "tags": [
        "AI",
        "AI Billing"
      ]
    },
    {
      "name": "Media",
      "tags": [
        "Media"
      ]
    },
    {
      "name": "Analytics & dashboard",
      "tags": [
        "Analytics",
        "Dashboard"
      ]
    },
    {
      "name": "Settings & views",
      "tags": [
        "View",
        "View Settings",
        "Website Settings",
        "Theme"
      ]
    },
    {
      "name": "Operations",
      "tags": [
        "Operation",
        "Search"
      ]
    },
    {
      "name": "Access",
      "tags": [
        "User",
        "User Profile",
        "Access"
      ]
    }
  ],
  "paths": {
    "/engine-api/v1/websites/{website_id}/media/{id}": {
      "get": {
        "operationId": "engineMediaGetHandler",
        "summary": "Get media",
        "description": "Serves a stored file, transformed on the fly. `w` and `h` fit the image inside a box; add `crop=1` to fill the box exactly and centre-crop the overflow; `q` sets the quality and `fmt` the output format. Every variant is derived from the original and cached, so asking for the size you will display costs nothing extra and is what a rendered page already does.\n\nThis is the one route of the engine surface the platform publishes, and it is unauthenticated by design: it is the URL a browser fetches from a public page.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the `media` resource this URL addresses.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "w",
            "in": "query",
            "description": "Target width in pixels (max 4096).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 4096
            }
          },
          {
            "name": "h",
            "in": "query",
            "description": "Target height in pixels (max 4096).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 4096
            }
          },
          {
            "name": "crop",
            "in": "query",
            "description": "Output exactly `w`\u00d7`h`, centre-cropping the overflow, instead of fitting inside the box. Needs both dimensions; only `1` and `true` enable it.",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "true"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Output quality, 1\u2013100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 85
            }
          },
          {
            "name": "fmt",
            "in": "query",
            "description": "Output format. Defaults to the stored format.",
            "schema": {
              "type": "string",
              "enum": [
                "jpeg",
                "png",
                "webp"
              ]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The stored bytes.",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/accounts": {
      "get": {
        "operationId": "accountListAccountsHandler",
        "summary": "List accounts",
        "description": "The top of the ownership tree: an account owns projects, a project owns websites, and a user reaches a website only through a membership in its account. The list is already scoped to the caller's own memberships, so there is nothing to filter by hand \u2014 and for the same reason its `total_size` counts what the caller can see, not what the platform holds.",
        "tags": [
          "Account"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`, `is_active`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `accounts`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accounts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Account"
                      },
                      "description": "This page of `accounts`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "accounts"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "accountCreateAccountHandler",
        "summary": "Create account",
        "description": "The top of the ownership tree: an account owns projects, a project owns websites, and a user reaches a website only through a membership in its account. The list is already scoped to the caller's own memberships, so there is nothing to filter by hand \u2014 and for the same reason its `total_size` counts what the caller can see, not what the platform holds.",
        "tags": [
          "Account"
        ],
        "x-method-kind": "CREATE",
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_agents": {
      "get": {
        "operationId": "aiAgentListHandler",
        "summary": "List ai_agents",
        "description": "The reusable settings of an AI run in an account: which instruction it follows, which model it runs on, how hard it tries and how long it waits. Every change is a new `version`, and the settings of each version are kept, so what any run used can be looked up later.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `allowed_model_ids`, `create_time`, `display_name`, `instruction_id`, `is_enabled`, `preferred_model_id`, `version`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_agents`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_agents": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiAgent"
                      },
                      "description": "This page of `ai_agents`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_agents"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "aiAgentCreateHandler",
        "summary": "Create ai_agent",
        "description": "Creates an agent at `version` 1. Name an instruction of the account with `instruction_id`, or set `source_system_agent` to copy a platform agent \u2014 its settings, and its instruction text as a new instruction of the account \u2014 with any other fields of the body applied over the copy.\n\nSettings that could never run are refused here rather than at the first run: a model that is not AVAILABLE, an `effort` on a model without the `EFFORT` capability, a JSON agent on a model without `STRUCTURED_OUTPUT`, a `max_tokens` above the model's limit.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiAgent"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiAgentCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_agents/{ai_agent_id}": {
      "delete": {
        "operationId": "aiAgentDeleteHandler",
        "summary": "Delete ai_agent",
        "description": "Deletes an agent. Its instruction is not deleted, and the settings of its versions are kept for the runs that used them, though they are no longer listed.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_agent`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "aiAgentGetHandler",
        "summary": "Get ai_agent",
        "description": "The reusable settings of an AI run in an account: which instruction it follows, which model it runs on, how hard it tries and how long it waits. Every change is a new `version`, and the settings of each version are kept, so what any run used can be looked up later.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_agent`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiAgent"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "aiAgentUpdateHandler",
        "summary": "Update ai_agent",
        "description": "Changes an agent's settings. Every update raises `version` by exactly one \u2014 even one that changes nothing \u2014 and keeps the settings of the version it replaces under `versions`. Send the `etag` in `If-Match` to be refused with ABORTED if someone else changed the agent first.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_agent`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiAgent"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiAgentUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_agents/{ai_agent_id}/versions": {
      "get": {
        "operationId": "aiAgentVersionListHandler",
        "summary": "List versions",
        "description": "The immutable settings of an agent at one version, written by the update that produced it. `create_time` is when that version took effect, so the settings in force at any moment are those of the latest version created before it.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The agent this is a version of. Fixed by the URL."
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `version desc`. Sortable: `version`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `created_by`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `versions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "versions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiAgentVersion"
                      },
                      "description": "This page of `versions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "versions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_agents/{ai_agent_id}/versions/{version}": {
      "get": {
        "operationId": "aiAgentVersionGetHandler",
        "summary": "Get version",
        "description": "The immutable settings of an agent at one version, written by the update that produced it. `create_time` is when that version took effect, so the settings in force at any moment are those of the latest version created before it.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The agent this is a version of. Fixed by the URL."
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The version number \u2014 also this resource's `id`, and the `version` the agent had.",
            "example": 4
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiAgentVersion"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_billing": {
      "get": {
        "operationId": "aiBillingGetHandler",
        "summary": "Get ai_billing",
        "description": "The account's AI balance, what it has spent today and this month, and the limits on that spending. Runs on the platform's key are paid from the balance and checked against the limits before they start; runs on the account's own provider key are not.",
        "tags": [
          "AI Billing"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiBilling"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "aiBillingUpdateHandler",
        "summary": "Update ai_billing",
        "description": "Sets the account's own limits on spending from the AI balance: `monthly_limit` and `daily_limit` as Money, and `max_concurrent_executions`. Clear a limit by naming it in `update_mask` with a `null` value. The balance cannot be changed here, and neither can the platform's ceilings shown beside the limits \u2014 the lower of each pair is the one in force.",
        "tags": [
          "AI Billing"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiBilling"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiBillingUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_connections": {
      "get": {
        "operationId": "aiConnectionListHandler",
        "summary": "List ai_connections",
        "description": "How an account's AI runs are authorized with a provider: its own API key (`BYOK`), or permission to use the platform's key and pay from the AI balance (`MANAGED`). Every account has one `MANAGED` connection per provider from the moment it exists; add `BYOK` connections for keys of your own.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`, `last_verify_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`, `is_enabled`, `mode`, `provider`, `status`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_connections`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_connections": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiConnection"
                      },
                      "description": "This page of `ai_connections`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_connections"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "aiConnectionCreateHandler",
        "summary": "Create ai_connection",
        "description": "Adds a way for the account's AI runs to be authorized. For your own provider key, send `mode: BYOK` with the `api_key`: it is encrypted before it is stored, only its last four characters come back as `key_hint`, and the connection starts `UNVERIFIED` \u2014 call `:verify` to have the provider confirm it.\n\nThe account's `MANAGED` connection for each provider already exists, so a `MANAGED` create answers ALREADY_EXISTS; `api_key` on a `MANAGED` connection is refused, because the platform's key is not the account's to set.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiConnection"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiConnectionCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_connections/{ai_connection_id}": {
      "delete": {
        "operationId": "aiConnectionDeleteHandler",
        "summary": "Delete ai_connection",
        "description": "Removes a `BYOK` connection and the key stored with it, for good. Runs stop using it at once. The account's `MANAGED` connection cannot be deleted \u2014 switch it off with `is_enabled: false`, which is how an account turns managed access off.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_connection_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_connection`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "aiConnectionGetHandler",
        "summary": "Get ai_connection",
        "description": "How an account's AI runs are authorized with a provider: its own API key (`BYOK`), or permission to use the platform's key and pay from the AI balance (`MANAGED`). Every account has one `MANAGED` connection per provider from the moment it exists; add `BYOK` connections for keys of your own.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_connection_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_connection`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiConnection"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "aiConnectionUpdateHandler",
        "summary": "Update ai_connection",
        "description": "Renames a connection, switches it on or off, or changes the order it is tried in. Sending a new `api_key` replaces the stored key: the old one is gone, `key_hint` changes, and the connection is `UNVERIFIED` again until it is checked \u2014 a verdict about the previous key says nothing about this one. `provider` and `mode` cannot be changed; create another connection.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_connection_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_connection`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiConnection"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiConnectionUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_connections/{ai_connection_id}:verify": {
      "post": {
        "operationId": "aiConnectionVerifyHandler",
        "summary": "Verify (ai_connections)",
        "description": "Asks the provider whether this connection's key still works, and records the answer: `status` becomes `VALID` or `INVALID` and `last_verify_time` is set. It uses the cheapest request that can tell, and costs no tokens. Answers with the connection either way \u2014 an `INVALID` key is the answer this call exists to give, not an error.\n\nFor a `BYOK` connection only. A `MANAGED` connection has no key of its own, so this call answers FAILED_PRECONDITION on one: the platform's key is checked by the platform.\n\nWhen the provider cannot be reached the call fails with UNAVAILABLE and nothing is changed: not being able to ask says nothing about the key. Safe to repeat.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_connection_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_connection`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:verify` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:verify`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_executions": {
      "get": {
        "operationId": "aiExecutionListHandler",
        "summary": "List ai_executions",
        "description": "One run of an agent in an account: what was asked, which model and connection ran it, what came back, what it consumed, and every attempt in between. Runs are carried out in the background \u2014 create one, then read it until `state` is final.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `expire_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `agent_id`, `connection_id`, `connection_mode`, `create_time`, `end_time`, `expire_time`, `model_id`, `provider`, `source_id`, `source_module`, `start_time`, `state`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_executions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_executions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiExecution"
                      },
                      "description": "This page of `ai_executions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_executions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "aiExecutionCreateHandler",
        "summary": "Create ai_execution",
        "description": "Starts a run of an agent and answers at once with the run, `QUEUED`: the work happens in the background, so read the run until `state` is `SUCCEEDED`, `FAILED`, `CANCELLED` or `EXPIRED`. The run uses the agent's current version and its instruction's active (or pinned) version, and keeps using them even if either changes before it starts.\n\nRefused before anything is queued: an `input` that does not fill exactly the variables the instruction uses, a `model_id` the agent cannot run on, an agent that is switched off, and an account with no connection the agent may use (FAILED_PRECONDITION, `NO_USABLE_CONNECTION`). Send a `request_id` to make the call safe to repeat: a repeat returns the first run.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiExecution"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiExecutionCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_executions/{ai_execution_id}": {
      "get": {
        "operationId": "aiExecutionGetHandler",
        "summary": "Get ai_execution",
        "description": "One run of an agent in an account: what was asked, which model and connection ran it, what came back, what it consumed, and every attempt in between. Runs are carried out in the background \u2014 create one, then read it until `state` is final.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_execution_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_execution`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiExecution"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_executions/{ai_execution_id}:cancel": {
      "post": {
        "operationId": "aiExecutionCancelHandler",
        "summary": "Cancel (ai_executions)",
        "description": "Stops a run. A `QUEUED` run is `CANCELLED` at once. A `RUNNING` run cannot be interrupted mid-call \u2014 the provider finishes what it was sent \u2014 so the cancel is recorded and the run becomes `CANCELLED` as soon as that call returns, without its output; until then it still reads `RUNNING`. A run that has already finished answers FAILED_PRECONDITION (`EXECUTION_FINISHED`). Safe to repeat.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_execution_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_execution`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:cancel` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:cancel`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_executions/{ai_execution_id}:retry": {
      "post": {
        "operationId": "aiExecutionRetryHandler",
        "summary": "Retry (ai_executions)",
        "description": "Runs a `FAILED` run again: it goes back to `QUEUED` with a fresh set of the agent's `max_attempts`, and the new attempts are added to `attempts` after the old ones, numbered on. It runs with the same agent version, instruction version, model and input. Any other state answers FAILED_PRECONDITION (`EXECUTION_NOT_FAILED`), as does a run past its `expire_time`.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_execution_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_execution`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:retry` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:retry`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_instructions": {
      "get": {
        "operationId": "aiInstructionListHandler",
        "summary": "List ai_instructions",
        "description": "A prompt template of an account, kept apart from the agents that use it so that its text has a history. The text itself lives in `versions`: writing a version is the only way to change it, and `active_version` says which one runs.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_instructions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_instructions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiInstruction"
                      },
                      "description": "This page of `ai_instructions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_instructions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "aiInstructionCreateHandler",
        "summary": "Create ai_instruction",
        "description": "Creates an instruction with its name and the variables its text may use, and no text yet: write the text as its first version (`POST \u2026/versions`), which becomes the active one.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiInstruction"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiInstructionCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_instructions/{ai_instruction_id}": {
      "delete": {
        "operationId": "aiInstructionDeleteHandler",
        "summary": "Delete ai_instruction",
        "description": "Deletes an instruction that no agent uses; while one does, the call fails with FAILED_PRECONDITION (`INSTRUCTION_IN_USE`). Past runs keep the text they used.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_instruction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_instruction`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "aiInstructionGetHandler",
        "summary": "Get ai_instruction",
        "description": "A prompt template of an account, kept apart from the agents that use it so that its text has a history. The text itself lives in `versions`: writing a version is the only way to change it, and `active_version` says which one runs.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_instruction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_instruction`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiInstruction"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "aiInstructionUpdateHandler",
        "summary": "Update ai_instruction",
        "description": "Renames an instruction, changes its `variables`, or switches the version that runs by setting `active_version`. The text itself does not change here \u2014 create a version for that. A change that would leave the active version referencing an undeclared variable is refused.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_instruction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_instruction`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiInstruction"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiInstructionUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_instructions/{ai_instruction_id}/versions": {
      "get": {
        "operationId": "aiInstructionVersionListHandler",
        "summary": "List versions",
        "description": "An immutable text of an instruction. Versions are numbered from 1 and never edited or deleted: to change the text, create the next version, then point the instruction's `active_version` at it if it is not the first.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_instruction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The instruction this is a version of. Fixed by the URL."
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `version desc`. Sortable: `version`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `created_by`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `versions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "versions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiInstructionVersion"
                      },
                      "description": "This page of `versions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "versions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "aiInstructionVersionCreateHandler",
        "summary": "Create version",
        "description": "Writes the next text of an instruction \u2014 the only way its text changes. The number is assigned by the server. The text may reference only the instruction's `variables`. The first version of an instruction becomes its `active_version`; a later one runs once the instruction is updated to point at it.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_instruction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The instruction this is a version of. Fixed by the URL."
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiInstructionVersion"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiInstructionVersionCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_instructions/{ai_instruction_id}/versions/{version}": {
      "get": {
        "operationId": "aiInstructionVersionGetHandler",
        "summary": "Get version",
        "description": "An immutable text of an instruction. Versions are numbered from 1 and never edited or deleted: to change the text, create the next version, then point the instruction's `active_version` at it if it is not the first.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_instruction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The instruction this is a version of. Fixed by the URL."
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The version number \u2014 also this resource's `id`. Assigned by the server: one more than the instruction's latest.",
            "example": 2
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiInstructionVersion"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_transactions": {
      "get": {
        "operationId": "aiTransactionListHandler",
        "summary": "List ai_transactions",
        "description": "The account's AI ledger: every charge for a run on the platform's key and every change the platform made to the balance, newest first. Rows are never edited or deleted \u2014 a correction is a row of its own.",
        "tags": [
          "AI Billing"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `execution_id`, `pricing_id`, `type`, `usage_record_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_transactions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_transactions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiTransaction"
                      },
                      "description": "This page of `ai_transactions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_transactions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_transactions/{ai_transaction_id}": {
      "get": {
        "operationId": "aiTransactionGetHandler",
        "summary": "Get ai_transaction",
        "description": "The account's AI ledger: every charge for a run on the platform's key and every change the platform made to the balance, newest first. Rows are never edited or deleted \u2014 a correction is a row of its own.",
        "tags": [
          "AI Billing"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_transaction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_transaction`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiTransaction"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_usage_records": {
      "get": {
        "operationId": "aiUsageRecordListHandler",
        "summary": "List ai_usage_records",
        "description": "What each attempt of the account's AI runs consumed, in tokens \u2014 for runs on the account's own provider key as much as for runs charged to the balance. One entry per attempt whose token counts the provider reported, newest first.",
        "tags": [
          "AI Billing"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `agent_id`, `connection_mode`, `create_time`, `execution_id`, `model_id`, `provider`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_usage_records`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_usage_records": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiUsageRecord"
                      },
                      "description": "This page of `ai_usage_records`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_usage_records"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/ai_usage_records/{ai_usage_record_id}": {
      "get": {
        "operationId": "aiUsageRecordGetHandler",
        "summary": "Get ai_usage_record",
        "description": "What each attempt of the account's AI runs consumed, in tokens \u2014 for runs on the account's own provider key as much as for runs charged to the balance. One entry per attempt whose token counts the provider reported, newest first.",
        "tags": [
          "AI Billing"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "ai_usage_record_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_usage_record`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiUsageRecord"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/invitations": {
      "get": {
        "operationId": "invitationListHandler",
        "summary": "List invitations",
        "description": "An invitation to join the account, mailed to an address with a one-time link. Whoever holds the link reads what it is for with `invitations:inspect` and takes it up with `invitations:accept` \u2014 signed in as the invited address, or as a new user choosing a password. Accepting makes a member with the invitation's `role` and uses the invitation up. Listing, reading, sending and withdrawing invitations take the `account.access` section.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `email asc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `email`, `role`, `state`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `invitations`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invitations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Invitation"
                      },
                      "description": "This page of `invitations`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "invitations"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "invitationCreateHandler",
        "summary": "Create invitation",
        "description": "Invites somebody to join the account: send `email`, `role` and \u2014 for `roles/sections` \u2014 the `grants`. A mail goes to the address with a one-time link, valid for 7 days, that opens the invitation in the admin app; the link is in the mail only and never in a response. Nobody may invite with a role or a grant wider than their own: that is PERMISSION_DENIED. An address that belongs to a member, or already has a pending invitation, is ALREADY_EXISTS on `email`. Send a `request_id` to make the call safe to repeat: a repeat returns the first invitation and mails nothing.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invitation"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvitationCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/invitations/{invitation_id}": {
      "delete": {
        "operationId": "invitationDeleteHandler",
        "summary": "Delete invitation",
        "description": "Withdraws an invitation: its link stops working at once, and the address may be invited again.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `invitation`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "invitationGetHandler",
        "summary": "Get invitation",
        "description": "An invitation to join the account, mailed to an address with a one-time link. Whoever holds the link reads what it is for with `invitations:inspect` and takes it up with `invitations:accept` \u2014 signed in as the invited address, or as a new user choosing a password. Accepting makes a member with the invitation's `role` and uses the invitation up. Listing, reading, sending and withdrawing invitations take the `account.access` section.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `invitation`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invitation"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/invitations/{invitation_id}:resend": {
      "post": {
        "operationId": "invitationResendHandler",
        "summary": "Resend (invitations)",
        "description": "Mails the invitation again with a new link and a new 7 days \u2014 pending or expired alike \u2014 and answers the invitation. The previous link stops working. Sending it again hands its role out again, so it takes holding that role, as sending it did.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `invitation`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:resend` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:resend`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/members": {
      "get": {
        "operationId": "memberListHandler",
        "summary": "List members",
        "description": "Who belongs to the account and what each of them may do. Listing the members, reading someone else's membership, changing a role and removing a member take the `account.access` section; every member may read their own membership, `members/{their user id}`, and leave the account by deleting it. The owner is a member too and cannot be removed or leave: ownership is handed over first.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `email asc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `email`, `is_owner`, `role`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `members`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Member"
                      },
                      "description": "This page of `members`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "members"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/members/{member_id}": {
      "delete": {
        "operationId": "memberDeleteHandler",
        "summary": "Delete member",
        "description": "Ends a membership. A member may delete their own and so leave the account; removing someone else takes `account.access: WRITE`. The owner can be neither removed nor leave \u2014 FAILED_PRECONDITION \u2014 until they hand the account over with `accounts/{account}:transfer_ownership`.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "member_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `member`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "memberGetHandler",
        "summary": "Get member",
        "description": "Reads one membership. Every member may read their own \u2014 `members/{their user id}`, with `is_owner` and the `effective_grants` a client builds its menus from; reading anyone else's takes `account.access`.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "member_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `member`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Member"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "memberUpdateHandler",
        "summary": "Update member",
        "description": "Changes a member's `role`, and the `grants` of a `roles/sections` membership. Takes `account.access: WRITE`, and nobody may give a role or a grant wider than their own \u2014 that is PERMISSION_DENIED; the owner and `roles/admin` hold everything, so they are never refused for it. The owner's own membership cannot be changed: FAILED_PRECONDITION.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "member_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `member`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Member"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MemberUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/projects": {
      "get": {
        "operationId": "projectListProjectsHandler",
        "summary": "List projects",
        "description": "A grouping of websites inside one account \u2014 the parent every website is created under. One project is enough for a single site; an agency keeps one per client.",
        "tags": [
          "Project"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The account this project belongs to. The URL already fixes it, so a write cannot move a project between accounts."
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`, `is_active`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `projects`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      },
                      "description": "This page of `projects`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "projects"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "projectCreateProjectHandler",
        "summary": "Create project",
        "description": "A grouping of websites inside one account \u2014 the parent every website is created under. One project is enough for a single site; an agency keeps one per client.",
        "tags": [
          "Project"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The account this project belongs to. The URL already fixes it, so a write cannot move a project between accounts."
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/projects/{id}": {
      "delete": {
        "operationId": "projectDeleteProjectHandler",
        "summary": "Delete project",
        "description": "A grouping of websites inside one account \u2014 the parent every website is created under. One project is enough for a single site; an agency keeps one per client.",
        "tags": [
          "Project"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The account this project belongs to. The URL already fixes it, so a write cannot move a project between accounts."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "projectGetProjectHandler",
        "summary": "Get project",
        "description": "A grouping of websites inside one account \u2014 the parent every website is created under. One project is enough for a single site; an agency keeps one per client.",
        "tags": [
          "Project"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The account this project belongs to. The URL already fixes it, so a write cannot move a project between accounts."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "projectUpdateProjectHandler",
        "summary": "Update project",
        "description": "A grouping of websites inside one account \u2014 the parent every website is created under. One project is enough for a single site; an agency keeps one per client.",
        "tags": [
          "Project"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The account this project belongs to. The URL already fixes it, so a write cannot move a project between accounts."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/roles": {
      "get": {
        "operationId": "accountRoleListHandler",
        "summary": "List roles",
        "description": "The account's own roles: named sets of grants, defined once and given to members and invitations by name \u2014 `role: accounts/{account}/roles/{role}` \u2014 beside the three roles every account has (`roles`). A member's rights follow the role, so changing its grants changes what every holder may do. Reading the roles takes the `account.access` section; defining, changing and deleting them takes writing it. A role that a member holds or an invitation names is not deleted, and deleting the account deletes its roles.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `display_name asc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `display_name`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `roles`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "roles": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AccountRole"
                      },
                      "description": "This page of `roles`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "roles"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "accountRoleCreateHandler",
        "summary": "Create role",
        "description": "Defines a role of the account: send `display_name`, and the `grants` it holds \u2014 the same `{permission, level}` a `roles/sections` membership carries \u2014 with an optional `description`. Give it to a member or an invitation by its name, `accounts/{account}/roles/{role}`. A name another role of the account has is ALREADY_EXISTS on `display_name`; nobody may define a role wider than their own: that is PERMISSION_DENIED.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRole"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountRoleCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{account_id}/roles/{role_id}": {
      "delete": {
        "operationId": "accountRoleDeleteHandler",
        "summary": "Delete role",
        "description": "Deletes a role nobody holds. While a member holds it, or an invitation \u2014 pending or expired \u2014 names it, the answer is FAILED_PRECONDITION: give those members another role and withdraw those invitations first.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "role_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `role`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "accountRoleGetHandler",
        "summary": "Get role",
        "description": "The account's own roles: named sets of grants, defined once and given to members and invitations by name \u2014 `role: accounts/{account}/roles/{role}` \u2014 beside the three roles every account has (`roles`). A member's rights follow the role, so changing its grants changes what every holder may do. Reading the roles takes the `account.access` section; defining, changing and deleting them takes writing it. A role that a member holds or an invitation names is not deleted, and deleting the account deletes its roles.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "role_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `role`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRole"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "accountRoleUpdateHandler",
        "summary": "Update role",
        "description": "Changes a role's `display_name`, `description` or `grants`. Every member holding the role holds the new grants from their next request. The grants as they will be are weighed against the caller's own, all of them: a role wider than the caller's is PERMISSION_DENIED.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `account`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "role_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `role`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRole"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountRoleUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{id}": {
      "delete": {
        "operationId": "accountDeleteAccountHandler",
        "summary": "Delete account",
        "description": "Deletes the account; its projects and its memberships go with it. Only the account's owner may: any other member \u2014 an administrator included \u2014 is refused PERMISSION_DENIED.",
        "tags": [
          "Account"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "accountGetAccountHandler",
        "summary": "Get account",
        "description": "The top of the ownership tree: an account owns projects, a project owns websites, and a user reaches a website only through a membership in its account. The list is already scoped to the caller's own memberships, so there is nothing to filter by hand \u2014 and for the same reason its `total_size` counts what the caller can see, not what the platform holds.",
        "tags": [
          "Account"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "accountUpdateAccountHandler",
        "summary": "Update account",
        "description": "The top of the ownership tree: an account owns projects, a project owns websites, and a user reaches a website only through a membership in its account. The list is already scoped to the caller's own memberships, so there is nothing to filter by hand \u2014 and for the same reason its `total_size` counts what the caller can see, not what the platform holds.",
        "tags": [
          "Account"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/accounts/{id}:transfer_ownership": {
      "post": {
        "operationId": "accountTransferOwnershipHandler",
        "summary": "Transfer ownership (accounts)",
        "description": "Hands the account to another of its members: send `{\"user\": \"users/{user}\"}`. Only the owner may \u2014 anyone else is refused PERMISSION_DENIED. The new owner must already be a member, otherwise the request is INVALID_ARGUMENT on `user`. The previous owner stays in the account as a `roles/admin` member, and the new owner's membership reads `roles/admin`, dormant while they own it. The response is the account, with its new `owner`.",
        "tags": [
          "Account"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the `accounts` resource this URL addresses.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:transfer_ownership` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:transfer_ownership`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/ai_models": {
      "get": {
        "operationId": "aiModelListHandler",
        "summary": "List ai_models",
        "description": "The models an AI agent can run on, with what each one can do. The catalogue belongs to the platform: read it to choose an agent's `preferred_model_id`. Prices are not part of a model \u2014 `platform_priced` says only whether there is one; what a run costs is recorded on the run.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `display_name asc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `capabilities`, `create_time`, `display_name`, `external_id`, `provider`, `state`, `tier`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_models`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_models": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiModel"
                      },
                      "description": "This page of `ai_models`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_models"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/ai_models/{ai_model_id}": {
      "get": {
        "operationId": "aiModelGetHandler",
        "summary": "Get ai_model",
        "description": "The models an AI agent can run on, with what each one can do. The catalogue belongs to the platform: read it to choose an agent's `preferred_model_id`. Prices are not part of a model \u2014 `platform_priced` says only whether there is one; what a run costs is recorded on the run.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "ai_model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_model`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiModel"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/ai_system_agents": {
      "get": {
        "operationId": "aiSystemAgentListHandler",
        "summary": "List ai_system_agents",
        "description": "The agents the platform ships, ready to copy into an account. Read one to see its instruction and settings; create an agent with `source_system_agent` set to its id to get a copy of your own. A copy does not follow later changes to the original.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `display_name asc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `ai_system_agents`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ai_system_agents": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AiSystemAgent"
                      },
                      "description": "This page of `ai_system_agents`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "ai_system_agents"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/ai_system_agents/{ai_system_agent_id}": {
      "get": {
        "operationId": "aiSystemAgentGetHandler",
        "summary": "Get ai_system_agent",
        "description": "The agents the platform ships, ready to copy into an account. Read one to see its instruction and settings; create an agent with `source_system_agent` set to its id to get a copy of your own. A copy does not follow later changes to the original.",
        "tags": [
          "AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "ai_system_agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `ai_system_agent`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiSystemAgent"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/dashboard_widget_types": {
      "get": {
        "operationId": "dashboardWidgetTypeListHandler",
        "summary": "List dashboard_widget_types",
        "description": "Every tile a dashboard can hold, with what it shows, how big it may be and what it can be configured with. Nothing here is stored or writable: it is the platform's catalogue, and a type your client does not recognise is one it should draw as a placeholder rather than drop \u2014 that is what lets the platform ship a new tile before your client knows about it. A saved dashboard is validated against this same list.",
        "tags": [
          "Dashboard"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `dashboard_widget_types`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dashboard_widget_types": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DashboardWidgetType"
                      },
                      "description": "This page of `dashboard_widget_types`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "dashboard_widget_types"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/dashboard_widget_types/{dashboard_widget_type_id}": {
      "get": {
        "operationId": "dashboardWidgetTypeGetHandler",
        "summary": "Get dashboard_widget_type",
        "description": "Every tile a dashboard can hold, with what it shows, how big it may be and what it can be configured with. Nothing here is stored or writable: it is the platform's catalogue, and a type your client does not recognise is one it should draw as a placeholder rather than drop \u2014 that is what lets the platform ship a new tile before your client knows about it. A saved dashboard is validated against this same list.",
        "tags": [
          "Dashboard"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "dashboard_widget_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `dashboard_widget_type`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardWidgetType"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/invitations:accept": {
      "post": {
        "operationId": "invitationAcceptHandler",
        "summary": "Accept (invitations)",
        "description": "Accepts an invitation: send the link's `token`. For a registered address, call it signed in as that address (`Authorization: Bearer \u2026`) \u2014 another user's session is PERMISSION_DENIED, no session UNAUTHENTICATED. For an address nobody is registered with, send a `password` (at least 8 characters) and, if you like, `firstname` and `lastname`: the user is made, and the answer carries their first session `token`. Either way the answer has the `user` and the `account` they joined, and the invitation is used up.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:accept` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:accept`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/invitations:inspect": {
      "post": {
        "operationId": "invitationInspectHandler",
        "summary": "Inspect (invitations)",
        "description": "Reads what an invitation link is for, without signing in: send the link's `{\"token\": \"\u2026\"}`. Answers `account_display_name`, the invited `email`, the `role` the membership will hold, `expire_time` and `user_exists` \u2014 whether the address is registered, which decides how it is accepted. A link that is wrong, expired, withdrawn or already used is NOT_FOUND, all alike.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:inspect` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:inspect`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/permissions": {
      "get": {
        "operationId": "permissionListHandler",
        "summary": "List permissions",
        "description": "The sections of the product a right can be granted on, as a tree: each has an `id` a grant names (`{permission, level}`, with `level` `READ` or `WRITE` \u2014 writing includes reading), and a grant on a section covers everything under it. Listed in tree order, each section right after its parent. Nothing here is stored or writable: it is the platform's catalogue, and a section a new release adds shows up here \u2014 and in every role that holds its parent \u2014 without anyone editing a role.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `permissions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "permissions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Permission"
                      },
                      "description": "This page of `permissions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "permissions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/permissions/{permission_id}": {
      "get": {
        "operationId": "permissionGetHandler",
        "summary": "Get permission",
        "description": "The sections of the product a right can be granted on, as a tree: each has an `id` a grant names (`{permission, level}`, with `level` `READ` or `WRITE` \u2014 writing includes reading), and a grant on a section covers everything under it. Listed in tree order, each section right after its parent. Nothing here is stored or writable: it is the platform's catalogue, and a section a new release adds shows up here \u2014 and in every role that holds its parent \u2014 without anyone editing a role.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "permission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `permission`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Permission"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/profile": {
      "get": {
        "operationId": "userProfileGetHandler",
        "summary": "Get profile",
        "description": "The signed-in user's own record. It is a singleton (\u00a79): there is no id in the URL because the bearer token already names whose profile this is, so there is no way to read anyone else's. Read it, patch it, or close the account with `profile:delete_account` \u2014 `DELETE` on a singleton is not a thing.",
        "tags": [
          "User Profile"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "userProfileUpdateHandler",
        "summary": "Update profile",
        "description": "The signed-in user's own record. It is a singleton (\u00a79): there is no id in the URL because the bearer token already names whose profile this is, so there is no way to read anyone else's. Read it, patch it, or close the account with `profile:delete_account` \u2014 `DELETE` on a singleton is not a thing.",
        "tags": [
          "User Profile"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProfileUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/profile:delete_account": {
      "post": {
        "operationId": "userProfileDeleteAccountHandler",
        "summary": "Delete account (profile)",
        "description": "Closes the signed-in user's own account. It is a custom method rather than a `DELETE` because a singleton has no Delete (\u00a79) \u2014 and because closing an account is not the same act as removing a row: it is irreversible, and it is the caller's own account, never anyone else's. The owner of an account that other members still belong to is refused FAILED_PRECONDITION, naming those accounts, until they hand each one over with `accounts/{account}:transfer_ownership`; an account they are the only member of is left without an owner.",
        "tags": [
          "User Profile"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:delete_account` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:delete_account`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/projects/{project_id}/websites": {
      "get": {
        "operationId": "websiteListWebsitesHandler",
        "summary": "List websites",
        "description": "The unit the platform publishes: one website is one site, with its own pages, blog, media, menus, themes, views and settings hanging off it. Creating one starts provisioning and answers with an Operation to poll (\u00a717) \u2014 the resource exists immediately, but it is not servable until that Operation is `done`. Everything else in this API is addressed under `websites/{website}`.",
        "tags": [
          "Website"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "project_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `parent`. Settable on create, immutable afterwards: a website does not move between projects.",
            "example": "9c2d40f7e1ab"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `code`, `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `code`, `create_time`, `display_name`, `is_active`, `project_id`, `provisioning_status`, `type`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `websites`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "websites": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Website"
                      },
                      "description": "This page of `websites`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "websites"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "websiteCreateWebsiteHandler",
        "summary": "Create website",
        "description": "The unit the platform publishes: one website is one site, with its own pages, blog, media, menus, themes, views and settings hanging off it. Creating one starts provisioning and answers with an Operation to poll (\u00a717) \u2014 the resource exists immediately, but it is not servable until that Operation is `done`. Everything else in this API is addressed under `websites/{website}`.",
        "tags": [
          "Website"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "project_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `parent`. Settable on create, immutable afterwards: a website does not move between projects.",
            "example": "9c2d40f7e1ab"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Website"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebsiteCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/roles": {
      "get": {
        "operationId": "roleListHandler",
        "summary": "List roles",
        "description": "The three roles every account has without defining them, which a membership names in its `role`: `roles/admin` \u2014 everything in the account, access management included, but not the owner's own acts; `roles/editor` \u2014 everything but access management; and `roles/sections` \u2014 only the sections its membership grants. The account's owner holds everything whatever the role says, and is the only one who may delete the account. Website content stays readable under every role, so pickers work; changing it takes a grant. An account defines roles of its own under `accounts/{account}/roles`.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `roles`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "roles": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Role"
                      },
                      "description": "This page of `roles`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "roles"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/roles/{role_id}": {
      "get": {
        "operationId": "roleGetHandler",
        "summary": "Get role",
        "description": "The three roles every account has without defining them, which a membership names in its `role`: `roles/admin` \u2014 everything in the account, access management included, but not the owner's own acts; `roles/editor` \u2014 everything but access management; and `roles/sections` \u2014 only the sections its membership grants. The account's owner holds everything whatever the role says, and is the only one who may delete the account. Website content stays readable under every role, so pickers work; changing it takes a grant. An account defines roles of its own under `accounts/{account}/roles`.",
        "tags": [
          "Access"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "role_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `role`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Role"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/setting_descriptors": {
      "get": {
        "operationId": "settingDescriptorListHandler",
        "summary": "List setting_descriptors",
        "description": "The registry of setting paths the platform knows about, and which of them may be overridden per view. It is read-only and it is not website-scoped: the paths come from the platform and its features, not from a tenant, which is exactly why a client cannot invent one by writing to `settings`.",
        "tags": [
          "View Settings"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `path asc`. Sortable: `path`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `path`, `view_overridable`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `setting_descriptors`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "setting_descriptors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SettingDescriptor"
                      },
                      "description": "This page of `setting_descriptors`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "setting_descriptors"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/users:authenticate": {
      "post": {
        "operationId": "userAuthenticateHandler",
        "summary": "Authenticate (users)",
        "description": "Exchanges an email and a password for the bearer JWT every other call on this surface needs. Send `{\"email\": \"...\", \"password\": \"...\"}`; the response carries `token`, the `user`, and the first active `account` they belong to. Send the token as `Authorization: Bearer <token>`.\n\nA wrong password and an unknown address answer the same UNAUTHENTICATED, on purpose: the difference between them is an answer to \"is this person registered here?\".",
        "tags": [
          "User"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:authenticate` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:authenticate`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/users:exchange_handoff": {
      "post": {
        "operationId": "userExchangeHandoffHandler",
        "summary": "Exchange handoff (users)",
        "description": "Trades the one-time `signup_token` from `POST /site-api/v1/users` for a bearer JWT, so a user who has just signed up is logged in without retyping the password they chose a moment ago. The token is single-use, short-lived, and burned on the first exchange.",
        "tags": [
          "User"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:exchange_handoff` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:exchange_handoff`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/users:reset_password": {
      "post": {
        "operationId": "userResetPasswordHandler",
        "summary": "Reset password (users)",
        "description": "Finishes a password reset: send the `token` from the mailed link together with the new `password`. The token is single-use and expires, so a link that has been used or sat too long is UNAUTHENTICATED rather than silently accepted.",
        "tags": [
          "User"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:reset_password` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:reset_password`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/users:send_password_reset": {
      "post": {
        "operationId": "userSendPasswordResetHandler",
        "summary": "Send password reset (users)",
        "description": "Starts a password reset: send `{\"email\": \"...\"}` and, if that address is registered, a mail goes out with a one-time link. The response is the same either way \u2014 a different answer for an unknown address would turn this into a way to enumerate accounts.",
        "tags": [
          "User"
        ],
        "x-method-kind": "CUSTOM",
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:send_password_reset` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:send_password_reset`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        }
      }
    },
    "/tenant-api/v1/websites/{id}": {
      "delete": {
        "operationId": "websiteDeleteWebsiteHandler",
        "summary": "Delete website",
        "description": "The unit the platform publishes: one website is one site, with its own pages, blog, media, menus, themes, views and settings hanging off it. Creating one starts provisioning and answers with an Operation to poll (\u00a717) \u2014 the resource exists immediately, but it is not servable until that Operation is `done`. Everything else in this API is addressed under `websites/{website}`.",
        "tags": [
          "Website"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "websiteGetWebsiteHandler",
        "summary": "Get website",
        "description": "The unit the platform publishes: one website is one site, with its own pages, blog, media, menus, themes, views and settings hanging off it. Creating one starts provisioning and answers with an Operation to poll (\u00a717) \u2014 the resource exists immediately, but it is not servable until that Operation is `done`. Everything else in this API is addressed under `websites/{website}`.",
        "tags": [
          "Website"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Website"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "websiteUpdateWebsiteHandler",
        "summary": "Update website",
        "description": "The unit the platform publishes: one website is one site, with its own pages, blog, media, menus, themes, views and settings hanging off it. Creating one starts provisioning and answers with an Operation to poll (\u00a717) \u2014 the resource exists immediately, but it is not servable until that Operation is `done`. Everything else in this API is addressed under `websites/{website}`.",
        "tags": [
          "Website"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Website"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebsiteUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/analytics_metrics": {
      "get": {
        "operationId": "analyticsMetricListHandler",
        "summary": "List analytics_metrics",
        "description": "What this website's analytics can count, one row per metric, with what each number means and which periods and intervals it accepts. Nothing here is stored or writable: it is the platform's catalogue, and a metric your client does not recognise is one it should skip rather than fail on. The numbers themselves come from `:query` on one of these rows.",
        "tags": [
          "Analytics"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `analytics_metrics`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "analytics_metrics": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AnalyticsMetric"
                      },
                      "description": "This page of `analytics_metrics`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "analytics_metrics"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/analytics_metrics/{analytics_metric_id}": {
      "get": {
        "operationId": "analyticsMetricGetHandler",
        "summary": "Get analytics_metric",
        "description": "What this website's analytics can count, one row per metric, with what each number means and which periods and intervals it accepts. Nothing here is stored or writable: it is the platform's catalogue, and a metric your client does not recognise is one it should skip rather than fail on. The numbers themselves come from `:query` on one of these rows.",
        "tags": [
          "Analytics"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "analytics_metric_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `analytics_metric`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsMetric"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/analytics_metrics/{analytics_metric_id}:query": {
      "get": {
        "operationId": "analyticsMetricQueryHandler",
        "summary": "Query (analytics_metrics)",
        "description": "Measures this metric over a window and answers the number, with the series behind it.\n\nA `GET` custom method, because it is a read no List filter can express (\u00a710): the answer is a measurement, not a resource, and it takes its arguments as query parameters.\n\nThe window comes back **resolved** \u2014 the absolute instants `TODAY` or `LAST_7_DAYS` turned out to be, and the `time_zone` the days were cut in, which is the website's own `tracking.site_analytics.time_zone` and neither the caller's nor the browser's. Without those two fields \"today\" is a number nobody can reproduce. `LAST_7_DAYS` and `LAST_30_DAYS` are whole days ending at today's local midnight; today itself is `TODAY`.\n\n`points` steps by `interval` and is absent \u2014 not empty \u2014 for a metric that has no series. `approximate` is `true` whenever the number came from a sketch rather than a counter.\n\nRefused rather than answered approximately: an `interval` the metric does not support, a range that would be more than 800 points, a range old enough to need minute buckets the retention no longer keeps, `start_time`/`end_time` on a named period or missing on a `CUSTOM` one, and a `filter` field other than `language`.",
        "tags": [
          "Analytics"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "analytics_metric_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `analytics_metric`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "period",
            "in": "query",
            "description": "Which window to measure. `CUSTOM` requires `start_time` and `end_time`; every other value refuses them. Days are cut in the website\u2019s own time zone, and the response says which instants that turned out to be.",
            "schema": {
              "type": "string",
              "default": "LAST_7_DAYS",
              "enum": [
                "TODAY",
                "LAST_7_DAYS",
                "LAST_30_DAYS",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "start_time",
            "in": "query",
            "description": "Inclusive start of a `CUSTOM` period, RFC 3339.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "end_time",
            "in": "query",
            "description": "Exclusive end of a `CUSTOM` period, RFC 3339.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "The step of the returned series. Defaults to `HOUR` for `TODAY` and `DAY` otherwise; a metric that supports no interval returns no series at all. A range that would exceed 800 points is INVALID_ARGUMENT.",
            "schema": {
              "type": "string",
              "enum": [
                "MINUTE",
                "HOUR",
                "DAY"
              ]
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `language`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "compare",
            "in": "query",
            "description": "Adds `previous_value`, measured over a window of equal length ending where this one starts.",
            "schema": {
              "type": "string",
              "enum": [
                "PREVIOUS_PERIOD"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "A measurement, not a resource: the `metric` measured, the `period` and `time_zone` it resolved to, the `interval`, the total `value`, `previous_value` when `compare` asked for one, `approximate` when the number came from a sketch rather than a counter, and `points[]` \u2014 `{start_time, end_time, value}` per interval, absent for a metric that has no series. A point carries its own end because the last one of a running period is shorter than the rest: the current hour is not over yet."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_authors": {
      "get": {
        "operationId": "blogAuthorListHandler",
        "summary": "List blog_authors",
        "description": "Someone a post can be credited to: a name, a slug, a portrait and a short biography. The name, the biography and the slug are translatable per view; the portrait and `is_active` are not.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`, `slug`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `audience`, `create_time`, `display_name`, `is_active`, `slug`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `blog_authors`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "blog_authors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogAuthor"
                      },
                      "description": "This page of `blog_authors`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "blog_authors"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogAuthorCreateHandler",
        "summary": "Create blog_author",
        "description": "Someone a post can be credited to: a name, a slug, a portrait and a short biography. The name, the biography and the slug are translatable per view; the portrait and `is_active` are not.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogAuthor"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogAuthorCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_authors/{author_id}/views": {
      "get": {
        "operationId": "blogAuthorViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master author: the name in the byline, the biography and the URL segment. The portrait and `is_active` stay on the author itself.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "author_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `author`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogAuthorView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogAuthorViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master author: the name in the byline, the biography and the URL segment. The portrait and `is_active` stay on the author itself.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "author_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `author`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogAuthorView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogAuthorViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_authors/{author_id}/views/{view_id}": {
      "delete": {
        "operationId": "blogAuthorViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master author: the name in the byline, the biography and the URL segment. The portrait and `is_active` stay on the author itself.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "author_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `author`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogAuthorViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master author: the name in the byline, the biography and the URL segment. The portrait and `is_active` stay on the author itself.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "author_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `author`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogAuthorView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogAuthorViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master author: the name in the byline, the biography and the URL segment. The portrait and `is_active` stay on the author itself.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "author_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `author`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogAuthorView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogAuthorViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_authors/{id}": {
      "delete": {
        "operationId": "blogAuthorDeleteHandler",
        "summary": "Delete blog_author",
        "description": "Someone a post can be credited to: a name, a slug, a portrait and a short biography. The name, the biography and the slug are translatable per view; the portrait and `is_active` are not.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogAuthorGetHandler",
        "summary": "Get blog_author",
        "description": "Someone a post can be credited to: a name, a slug, a portrait and a short biography. The name, the biography and the slug are translatable per view; the portrait and `is_active` are not.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogAuthor"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogAuthorUpdateHandler",
        "summary": "Update blog_author",
        "description": "Someone a post can be credited to: a name, a slug, a portrait and a short biography. The name, the biography and the slug are translatable per view; the portrait and `is_active` are not.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogAuthor"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogAuthorUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_categories": {
      "get": {
        "operationId": "blogCategoryListHandler",
        "summary": "List blog_categories",
        "description": "A section of the blog. Categories form a tree: `parent_id` names the one above, `path` and `url_path` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. `:set_posts` replaces the posts of one category in a single call.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `path asc`. Sortable: `create_time`, `path`, `sort_order`, `url_path`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `audience`, `create_time`, `display_name`, `is_active`, `parent_id`, `path`, `slug`, `url_path`, `visible_view_ids`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `blog_categories`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "blog_categories": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogCategory"
                      },
                      "description": "This page of `blog_categories`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "blog_categories"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogCategoryCreateHandler",
        "summary": "Create blog_category",
        "description": "A section of the blog. Categories form a tree: `parent_id` names the one above, `path` and `url_path` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. `:set_posts` replaces the posts of one category in a single call.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategory"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogCategoryCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_categories/{category_id}/views": {
      "get": {
        "operationId": "blogCategoryViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master category: its name, its blurb and its URL segment. The shape of the tree is not overridable \u2014 a category has the same parent and the same siblings in every view.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `category`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogCategoryView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogCategoryViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master category: its name, its blurb and its URL segment. The shape of the tree is not overridable \u2014 a category has the same parent and the same siblings in every view.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `category`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategoryView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogCategoryViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_categories/{category_id}/views/{view_id}": {
      "delete": {
        "operationId": "blogCategoryViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master category: its name, its blurb and its URL segment. The shape of the tree is not overridable \u2014 a category has the same parent and the same siblings in every view.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `category`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogCategoryViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master category: its name, its blurb and its URL segment. The shape of the tree is not overridable \u2014 a category has the same parent and the same siblings in every view.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `category`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategoryView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogCategoryViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master category: its name, its blurb and its URL segment. The shape of the tree is not overridable \u2014 a category has the same parent and the same siblings in every view.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `category`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategoryView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogCategoryViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_categories/{id}": {
      "delete": {
        "operationId": "blogCategoryDeleteHandler",
        "summary": "Delete blog_category",
        "description": "A section of the blog. Categories form a tree: `parent_id` names the one above, `path` and `url_path` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. `:set_posts` replaces the posts of one category in a single call.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogCategoryGetHandler",
        "summary": "Get blog_category",
        "description": "A section of the blog. Categories form a tree: `parent_id` names the one above, `path` and `url_path` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. `:set_posts` replaces the posts of one category in a single call.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategory"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogCategoryUpdateHandler",
        "summary": "Update blog_category",
        "description": "A section of the blog. Categories form a tree: `parent_id` names the one above, `path` and `url_path` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. `:set_posts` replaces the posts of one category in a single call.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategory"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogCategoryUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_categories/{id}:move": {
      "post": {
        "operationId": "blogCategoryMoveHandler",
        "summary": "Move (blog_categories)",
        "description": "Moves a category inside the tree. Send `{\"parent_id\": ..., \"after_id\": ...}`: `parent_id` absent or null means the root, `after_id` absent or null means first among its new siblings.\n\nThis is the only way to re-parent or reorder a category \u2014 `parent_id` is immutable on Update \u2014 because the move is what rewrites `path`, `url_path`, `level` and `sort_order` for the whole subtree. It answers with the moved category, so those recomputed fields need no second read.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the `blog_categories` resource this URL addresses.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:move` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:move`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_categories/{id}:set_posts": {
      "post": {
        "operationId": "blogCategorySetPostsHandler",
        "summary": "Set posts (blog_categories)",
        "description": "Replaces the posts of one category in a single call: send `{\"post_ids\": [...]}` and the category ends up with exactly those, in that order. It is a write on the category, not a sub-collection \u2014 which is why it is a custom method and not a `POST` to a `posts` collection that does not exist.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the `blog_categories` resource this URL addresses.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:set_posts` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:set_posts`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_posts": {
      "get": {
        "operationId": "blogPostListHandler",
        "summary": "List blog_posts",
        "description": "One article of the website's blog: headline, slug, teaser, rich-text body, byline and dates, plus the categories and tags it belongs to. What a view says instead lives in its `views` overlay, and a post is live when `is_active` is true and `publish_time` has passed.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `is_active`, `publish_time`, `slug`, `title`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `audience`, `author_id`, `category_ids`, `create_time`, `is_active`, `publish_time`, `slug`, `tag_ids`, `title`, `visible_view_ids`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `blog_posts`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "blog_posts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogPost"
                      },
                      "description": "This page of `blog_posts`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "blog_posts"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogPostCreateHandler",
        "summary": "Create blog_post",
        "description": "One article of the website's blog: headline, slug, teaser, rich-text body, byline and dates, plus the categories and tags it belongs to. What a view says instead lives in its `views` overlay, and a post is live when `is_active` is true and `publish_time` has passed.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPost"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogPostCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_posts/{id}": {
      "delete": {
        "operationId": "blogPostDeleteHandler",
        "summary": "Delete blog_post",
        "description": "One article of the website's blog: headline, slug, teaser, rich-text body, byline and dates, plus the categories and tags it belongs to. What a view says instead lives in its `views` overlay, and a post is live when `is_active` is true and `publish_time` has passed.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogPostGetHandler",
        "summary": "Get blog_post",
        "description": "One article of the website's blog: headline, slug, teaser, rich-text body, byline and dates, plus the categories and tags it belongs to. What a view says instead lives in its `views` overlay, and a post is live when `is_active` is true and `publish_time` has passed.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPost"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogPostUpdateHandler",
        "summary": "Update blog_post",
        "description": "One article of the website's blog: headline, slug, teaser, rich-text body, byline and dates, plus the categories and tags it belongs to. What a view says instead lives in its `views` overlay, and a post is live when `is_active` is true and `publish_time` has passed.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPost"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogPostUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_posts/{post_id}/views": {
      "get": {
        "operationId": "blogPostViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master post \u2014 headline, slug, teaser, body, SEO metadata and lead image. Every field falls back to the post, and `overridden` decides which of them this view claims.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "post_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `post`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogPostView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogPostViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master post \u2014 headline, slug, teaser, body, SEO metadata and lead image. Every field falls back to the post, and `overridden` decides which of them this view claims.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "post_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `post`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogPostViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_posts/{post_id}/views/{view_id}": {
      "delete": {
        "operationId": "blogPostViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master post \u2014 headline, slug, teaser, body, SEO metadata and lead image. Every field falls back to the post, and `overridden` decides which of them this view claims.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "post_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `post`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogPostViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master post \u2014 headline, slug, teaser, body, SEO metadata and lead image. Every field falls back to the post, and `overridden` decides which of them this view claims.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "post_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `post`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogPostViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master post \u2014 headline, slug, teaser, body, SEO metadata and lead image. Every field falls back to the post, and `overridden` decides which of them this view claims.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "post_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `post`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogPostViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_tags": {
      "get": {
        "operationId": "blogTagListHandler",
        "summary": "List blog_tags",
        "description": "A flat label a post can carry \u2014 the cross-cutting counterpart of a category, which is a place in a tree. A tag is two fields and its per-view overlay; posts are attached from the post's own `tag_ids`.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `display_name asc`. Sortable: `create_time`, `display_name`, `slug`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `audience`, `create_time`, `display_name`, `slug`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `blog_tags`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "blog_tags": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogTag"
                      },
                      "description": "This page of `blog_tags`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "blog_tags"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogTagCreateHandler",
        "summary": "Create blog_tag",
        "description": "A flat label a post can carry \u2014 the cross-cutting counterpart of a category, which is a place in a tree. A tag is two fields and its per-view overlay; posts are attached from the post's own `tag_ids`.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogTag"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogTagCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_tags/{id}": {
      "delete": {
        "operationId": "blogTagDeleteHandler",
        "summary": "Delete blog_tag",
        "description": "A flat label a post can carry \u2014 the cross-cutting counterpart of a category, which is a place in a tree. A tag is two fields and its per-view overlay; posts are attached from the post's own `tag_ids`.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogTagGetHandler",
        "summary": "Get blog_tag",
        "description": "A flat label a post can carry \u2014 the cross-cutting counterpart of a category, which is a place in a tree. A tag is two fields and its per-view overlay; posts are attached from the post's own `tag_ids`.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogTag"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogTagUpdateHandler",
        "summary": "Update blog_tag",
        "description": "A flat label a post can carry \u2014 the cross-cutting counterpart of a category, which is a place in a tree. A tag is two fields and its per-view overlay; posts are attached from the post's own `tag_ids`.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogTag"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogTagUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_tags/{tag_id}/views": {
      "get": {
        "operationId": "blogTagViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master tag: its name and its URL segment. Which posts carry the tag is not a per-view decision.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "tag_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `tag`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogTagView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "blogTagViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master tag: its name and its URL segment. Which posts carry the tag is not a per-view decision.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "tag_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `tag`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogTagView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogTagViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/blog_tags/{tag_id}/views/{view_id}": {
      "delete": {
        "operationId": "blogTagViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master tag: its name and its URL segment. Which posts carry the tag is not a per-view decision.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "tag_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `tag`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "blogTagViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master tag: its name and its URL segment. Which posts carry the tag is not a per-view decision.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "tag_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `tag`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogTagView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "blogTagViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master tag: its name and its URL segment. Which posts carry the tag is not a per-view decision.",
        "tags": [
          "Blog"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "tag_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `tag`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogTagView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogTagViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_blocks": {
      "get": {
        "operationId": "cmsBlockListCmsBlocksHandler",
        "summary": "List cms_blocks",
        "description": "A reusable fragment of content, addressed by its `identifier` and pulled into pages, themes and smart links rather than into a URL of its own. Footers, contact strips, banners \u2014 anything that has to say the same thing in several places and change in one.",
        "tags": [
          "CMS Block"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `identifier`, `title`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `identifier`, `is_active`, `title`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `cms_blocks`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cms_blocks": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CmsBlock"
                      },
                      "description": "This page of `cms_blocks`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "cms_blocks"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "cmsBlockCreateCmsBlockHandler",
        "summary": "Create cms_block",
        "description": "A reusable fragment of content, addressed by its `identifier` and pulled into pages, themes and smart links rather than into a URL of its own. Footers, contact strips, banners \u2014 anything that has to say the same thing in several places and change in one.",
        "tags": [
          "CMS Block"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsBlock"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsBlockCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_blocks/{block_id}/views": {
      "get": {
        "operationId": "cmsBlockViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master block. A block has one field worth translating, so this is the smallest overlay in the API \u2014 but it works exactly like the others: optional fields, a fallback to the master, and `overridden` deciding which of them this view claims.",
        "tags": [
          "CMS Block View"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "block_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `block`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CmsBlockView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "cmsBlockViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master block. A block has one field worth translating, so this is the smallest overlay in the API \u2014 but it works exactly like the others: optional fields, a fallback to the master, and `overridden` deciding which of them this view claims.",
        "tags": [
          "CMS Block View"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "block_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `block`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsBlockView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsBlockViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_blocks/{block_id}/views/{view_id}": {
      "delete": {
        "operationId": "cmsBlockViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master block. A block has one field worth translating, so this is the smallest overlay in the API \u2014 but it works exactly like the others: optional fields, a fallback to the master, and `overridden` deciding which of them this view claims.",
        "tags": [
          "CMS Block View"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "block_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `block`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "cmsBlockViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master block. A block has one field worth translating, so this is the smallest overlay in the API \u2014 but it works exactly like the others: optional fields, a fallback to the master, and `overridden` deciding which of them this view claims.",
        "tags": [
          "CMS Block View"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "block_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `block`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsBlockView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "cmsBlockViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master block. A block has one field worth translating, so this is the smallest overlay in the API \u2014 but it works exactly like the others: optional fields, a fallback to the master, and `overridden` deciding which of them this view claims.",
        "tags": [
          "CMS Block View"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "block_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `block`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsBlockView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsBlockViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_blocks/{id}": {
      "delete": {
        "operationId": "cmsBlockDeleteCmsBlockHandler",
        "summary": "Delete cms_block",
        "description": "A reusable fragment of content, addressed by its `identifier` and pulled into pages, themes and smart links rather than into a URL of its own. Footers, contact strips, banners \u2014 anything that has to say the same thing in several places and change in one.",
        "tags": [
          "CMS Block"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "cmsBlockGetCmsBlockHandler",
        "summary": "Get cms_block",
        "description": "A reusable fragment of content, addressed by its `identifier` and pulled into pages, themes and smart links rather than into a URL of its own. Footers, contact strips, banners \u2014 anything that has to say the same thing in several places and change in one.",
        "tags": [
          "CMS Block"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsBlock"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "cmsBlockUpdateCmsBlockHandler",
        "summary": "Update cms_block",
        "description": "A reusable fragment of content, addressed by its `identifier` and pulled into pages, themes and smart links rather than into a URL of its own. Footers, contact strips, banners \u2014 anything that has to say the same thing in several places and change in one.",
        "tags": [
          "CMS Block"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsBlock"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsBlockUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_pages": {
      "get": {
        "operationId": "cmsPageListCmsPagesHandler",
        "summary": "List cms_pages",
        "description": "A page of the site \u2014 its title, its slug, its rich-text body and its SEO metadata. A page is one resource for the whole website: what one view says instead of the master lives in its `views` overlay, and which views show it at all is `visible_view_ids`. Which visitors may read it is `audience`.",
        "tags": [
          "CMS Page"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `title`, `url_key`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `audience`, `create_time`, `is_active`, `title`, `url_key`, `visible_view_ids`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `cms_pages`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cms_pages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CmsPage"
                      },
                      "description": "This page of `cms_pages`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "cms_pages"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "cmsPageCreateCmsPageHandler",
        "summary": "Create cms_page",
        "description": "A page of the site \u2014 its title, its slug, its rich-text body and its SEO metadata. A page is one resource for the whole website: what one view says instead of the master lives in its `views` overlay, and which views show it at all is `visible_view_ids`. Which visitors may read it is `audience`.",
        "tags": [
          "CMS Page"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPage"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsPageCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_pages/{id}": {
      "delete": {
        "operationId": "cmsPageDeleteCmsPageHandler",
        "summary": "Delete cms_page",
        "description": "A page of the site \u2014 its title, its slug, its rich-text body and its SEO metadata. A page is one resource for the whole website: what one view says instead of the master lives in its `views` overlay, and which views show it at all is `visible_view_ids`. Which visitors may read it is `audience`.",
        "tags": [
          "CMS Page"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "cmsPageGetCmsPageHandler",
        "summary": "Get cms_page",
        "description": "A page of the site \u2014 its title, its slug, its rich-text body and its SEO metadata. A page is one resource for the whole website: what one view says instead of the master lives in its `views` overlay, and which views show it at all is `visible_view_ids`. Which visitors may read it is `audience`.",
        "tags": [
          "CMS Page"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPage"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "cmsPageUpdateCmsPageHandler",
        "summary": "Update cms_page",
        "description": "A page of the site \u2014 its title, its slug, its rich-text body and its SEO metadata. A page is one resource for the whole website: what one view says instead of the master lives in its `views` overlay, and which views show it at all is `visible_view_ids`. Which visitors may read it is `audience`.",
        "tags": [
          "CMS Page"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPage"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsPageUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_pages/{page_id}/group_versions": {
      "get": {
        "operationId": "cmsPageGroupVersionListHandler",
        "summary": "List group_versions",
        "description": "What the customers of one group see of a page instead of the page itself: its text, its title, its hero \u2014 a price or a condition meant for them. A signed-in customer in several groups that each have a version sees the version of the group with the highest `priority`; everybody else, the page. A version is the same on every view, and never changes where the page lives or who may read it.",
        "tags": [
          "CMS Page Group"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `customer_group_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `group_versions`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "group_versions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CmsPageGroupVersion"
                      },
                      "description": "This page of `group_versions`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "group_versions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "cmsPageGroupVersionCreateHandler",
        "summary": "Create group_version",
        "description": "Adds a version of the page for one customer group of the website. `customer_group_id` is required and must name a group of the same website; a group that already has a version of the page answers ALREADY_EXISTS. Each name in `overridden` must be one of the fields a version can override.",
        "tags": [
          "CMS Page Group"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPageGroupVersion"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsPageGroupVersionCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_pages/{page_id}/group_versions/{version_id}": {
      "delete": {
        "operationId": "cmsPageGroupVersionDeleteHandler",
        "summary": "Delete group_version",
        "description": "Deletes a version: the customers of its group see the page itself again.",
        "tags": [
          "CMS Page Group"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "version_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `version`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "cmsPageGroupVersionGetHandler",
        "summary": "Get group_version",
        "description": "What the customers of one group see of a page instead of the page itself: its text, its title, its hero \u2014 a price or a condition meant for them. A signed-in customer in several groups that each have a version sees the version of the group with the highest `priority`; everybody else, the page. A version is the same on every view, and never changes where the page lives or who may read it.",
        "tags": [
          "CMS Page Group"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "version_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `version`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPageGroupVersion"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "cmsPageGroupVersionUpdateHandler",
        "summary": "Update group_version",
        "description": "Changes a version. `customer_group_id` is fixed and refused here; a version for another group is a new version.",
        "tags": [
          "CMS Page Group"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "version_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `version`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPageGroupVersion"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsPageGroupVersionUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_pages/{page_id}/views": {
      "get": {
        "operationId": "cmsPageViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master page. Every field here is optional and every one of them falls back to the page itself; `overridden` is the list that decides which of them this view actually claims. The collection is bounded by the number of views on the website and is served whole.",
        "tags": [
          "CMS Page View"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CmsPageView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "cmsPageViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master page. Every field here is optional and every one of them falls back to the page itself; `overridden` is the list that decides which of them this view actually claims. The collection is bounded by the number of views on the website and is served whole.",
        "tags": [
          "CMS Page View"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPageView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsPageViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/cms_pages/{page_id}/views/{view_id}": {
      "delete": {
        "operationId": "cmsPageViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master page. Every field here is optional and every one of them falls back to the page itself; `overridden` is the list that decides which of them this view actually claims. The collection is bounded by the number of views on the website and is served whole.",
        "tags": [
          "CMS Page View"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "cmsPageViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master page. Every field here is optional and every one of them falls back to the page itself; `overridden` is the list that decides which of them this view actually claims. The collection is bounded by the number of views on the website and is served whole.",
        "tags": [
          "CMS Page View"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPageView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "cmsPageViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master page. Every field here is optional and every one of them falls back to the page itself; `overridden` is the list that decides which of them this view actually claims. The collection is bounded by the number of views on the website and is served whole.",
        "tags": [
          "CMS Page View"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `page`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CmsPageView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CmsPageViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/custom_domain": {
      "get": {
        "operationId": "customDomainStatusHandler",
        "summary": "Get custom_domain",
        "description": "Where this website answers, and how far a custom domain has got: the platform hostname it always has, the custom hostname if one is configured, the DNS records to publish, and whether the platform can see them yet.\n\nRead-only on purpose. The hostname itself is written through the `general.web.custom_domain` setting \u2014 this resource is the connection's status, not its configuration.",
        "tags": [
          "Custom Domain"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The custom-domain singleton (\u00a79): connection state, verification records and status."
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/custom_domain:verify": {
      "post": {
        "operationId": "customDomainVerifyHandler",
        "summary": "Verify (custom_domain)",
        "description": "Re-checks the DNS of the configured custom domain now, instead of waiting for the platform to look again. Use it after publishing the records this resource asked for. It answers with the same status body, so one call both triggers the check and reports the result.",
        "tags": [
          "Custom Domain"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:verify` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:verify`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_attribute_groups": {
      "get": {
        "operationId": "customerAttributeGroupListHandler",
        "summary": "List customer_attribute_groups",
        "description": "A section the customer form in the admin gathers customer attributes under \u2014 \u00abPersonal\u00bb, \u00abPreferences\u00bb. An attribute names its section in `group_id`; the registration form on the site lists its fields flat and ignores sections. Deleting a section moves its attributes to the default one. At most 20 per website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `sort_order asc`. Sortable: `sort_order`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `display_name`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `customer_attribute_groups`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer_attribute_groups": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerAttributeGroup"
                      },
                      "description": "This page of `customer_attribute_groups`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "customer_attribute_groups"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "customerAttributeGroupCreateHandler",
        "summary": "Create customer_attribute_group",
        "description": "Adds a section. `display_name` is required; a website that already has 20 sections answers FAILED_PRECONDITION. The new section comes last in `sort_order`.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAttributeGroup"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerAttributeGroupCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_attribute_groups/{attribute_group_id}": {
      "delete": {
        "operationId": "customerAttributeGroupDeleteHandler",
        "summary": "Delete customer_attribute_group",
        "description": "Deletes a section and moves every field in it to the default section \u2014 `group_id` cleared \u2014 before it answers. The fields themselves stay.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute_group`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "customerAttributeGroupGetHandler",
        "summary": "Get customer_attribute_group",
        "description": "A section the customer form in the admin gathers customer attributes under \u2014 \u00abPersonal\u00bb, \u00abPreferences\u00bb. An attribute names its section in `group_id`; the registration form on the site lists its fields flat and ignores sections. Deleting a section moves its attributes to the default one. At most 20 per website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute_group`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAttributeGroup"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "customerAttributeGroupUpdateHandler",
        "summary": "Update customer_attribute_group",
        "description": "A section the customer form in the admin gathers customer attributes under \u2014 \u00abPersonal\u00bb, \u00abPreferences\u00bb. An attribute names its section in `group_id`; the registration form on the site lists its fields flat and ignores sections. Deleting a section moves its attributes to the default one. At most 20 per website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute_group`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAttributeGroup"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerAttributeGroupUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_attribute_groups/{attribute_group_id}:move": {
      "post": {
        "operationId": "customerAttributeGroupMoveHandler",
        "summary": "Move (customer_attribute_groups)",
        "description": "Moves a section to another place among the website's sections. Send `{\"after_id\": \"...\"}` to put it right after that section, or `{\"after_id\": null}` (or `{}`) to put it first. Answers the moved section with its new `sort_order`; the other sections are renumbered around it.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute_group`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:move` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:move`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_attributes": {
      "get": {
        "operationId": "customerAttributeListHandler",
        "summary": "List customer_attributes",
        "description": "A field the tenant adds to the website's customers \u2014 a birth date, a loyalty number, a preferred store \u2014 with its type, its label in each language, whether it is required and whether the registration form asks for it. A customer's values are kept in their `attributes` under the field's `key`. A field is switched off with `is_active` rather than deleted when its values are worth keeping: deleting it removes them from every customer. At most 100 per website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `sort_order asc`. Sortable: `key`, `sort_order`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `display_name`, `group_id`, `is_active`, `is_required`, `key`, `show_in_registration`, `type`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `customer_attributes`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer_attributes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerAttribute"
                      },
                      "description": "This page of `customer_attributes`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "customer_attributes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "customerAttributeCreateHandler",
        "summary": "Create customer_attribute",
        "description": "Adds a field to the website's customers. `key`, `display_name` and `type` are required; a `key` another field of the website has answers ALREADY_EXISTS, and a website that already has 100 fields answers FAILED_PRECONDITION. The new field comes last in `sort_order`.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAttribute"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerAttributeCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_attributes/{attribute_id}": {
      "delete": {
        "operationId": "customerAttributeDeleteHandler",
        "summary": "Delete customer_attribute",
        "description": "Deletes a field. Switch `is_active` off instead to keep the values customers hold under it.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "customerAttributeGetHandler",
        "summary": "Get customer_attribute",
        "description": "A field the tenant adds to the website's customers \u2014 a birth date, a loyalty number, a preferred store \u2014 with its type, its label in each language, whether it is required and whether the registration form asks for it. A customer's values are kept in their `attributes` under the field's `key`. A field is switched off with `is_active` rather than deleted when its values are worth keeping: deleting it removes them from every customer. At most 100 per website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAttribute"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "customerAttributeUpdateHandler",
        "summary": "Update customer_attribute",
        "description": "Changes a field. `key` and `type` are fixed and refused here, and `sort_order` is changed with `:move`. The result is checked as a whole: `options` only on `SELECT` and `MULTISELECT`, a length only on `TEXT` and `TEXTAREA`, a range only on `NUMBER`.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAttribute"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerAttributeUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_attributes/{attribute_id}:move": {
      "post": {
        "operationId": "customerAttributeMoveHandler",
        "summary": "Move (customer_attributes)",
        "description": "Moves a field to another place among the website's fields. Send `{\"after_id\": \"...\"}` to put it right after that field, or `{\"after_id\": null}` (or `{}`) to put it first. Answers the moved field with its new `sort_order`; the other fields are renumbered around it.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "attribute_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `attribute`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:move` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:move`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_groups": {
      "get": {
        "operationId": "customerGroupListHandler",
        "summary": "List customer_groups",
        "description": "A group the website's customers are segmented into \u2014 what a page can be shown to or hidden from, and whose version of a page a customer sees. A `MANUAL` group holds the customers assigned to it; a `DYNAMIC` one holds whoever matches its rule. Deleting a group takes it off every customer.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`, `priority`, `type`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `customer_groups`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer_groups": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerGroup"
                      },
                      "description": "This page of `customer_groups`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "customer_groups"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "customerGroupCreateHandler",
        "summary": "Create customer_group",
        "description": "A group the website's customers are segmented into \u2014 what a page can be shown to or hidden from, and whose version of a page a customer sees. A `MANUAL` group holds the customers assigned to it; a `DYNAMIC` one holds whoever matches its rule. Deleting a group takes it off every customer.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGroup"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerGroupCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customer_groups/{customer_group_id}": {
      "delete": {
        "operationId": "customerGroupDeleteHandler",
        "summary": "Delete customer_group",
        "description": "Deletes a group and takes it off every customer who was in it \u2014 out of `manual_group_ids` and `group_ids` alike \u2014 before it answers.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "customer_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `customer_group`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "customerGroupGetHandler",
        "summary": "Get customer_group",
        "description": "A group the website's customers are segmented into \u2014 what a page can be shown to or hidden from, and whose version of a page a customer sees. A `MANUAL` group holds the customers assigned to it; a `DYNAMIC` one holds whoever matches its rule. Deleting a group takes it off every customer.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "customer_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `customer_group`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGroup"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "customerGroupUpdateHandler",
        "summary": "Update customer_group",
        "description": "A group the website's customers are segmented into \u2014 what a page can be shown to or hidden from, and whose version of a page a customer sees. A `MANUAL` group holds the customers assigned to it; a `DYNAMIC` one holds whoever matches its rule. Deleting a group takes it off every customer.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "customer_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `customer_group`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGroup"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerGroupUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customers": {
      "get": {
        "operationId": "customerListHandler",
        "summary": "List customers",
        "description": "A visitor who has an account on the website \u2014 registered on the site itself or added here by the tenant. A customer belongs to one website: the same address on another website is another customer. Groups are assigned by hand in `manual_group_ids`; `group_ids` is the resulting membership. The fields the website adds to its customers are filled in `attributes`.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `email`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`, `email`, `is_active`, `tags`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `customers`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customers": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      },
                      "description": "This page of `customers`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "customers"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "customerCreateHandler",
        "summary": "Create customer",
        "description": "Adds a customer to the website, as if they had registered on it: `email` and `password` are required, and an address the website already has answers ALREADY_EXISTS. Groups are given in `manual_group_ids` and must be `MANUAL` groups of the same website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/customers/{customer_id}": {
      "delete": {
        "operationId": "customerDeleteHandler",
        "summary": "Delete customer",
        "description": "Deletes a customer together with their sessions: whoever was signed in as them is signed out. The address becomes free to register again.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `customer`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "customerGetHandler",
        "summary": "Get customer",
        "description": "A visitor who has an account on the website \u2014 registered on the site itself or added here by the tenant. A customer belongs to one website: the same address on another website is another customer. Groups are assigned by hand in `manual_group_ids`; `group_ids` is the resulting membership. The fields the website adds to its customers are filled in `attributes`.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `customer`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "customerUpdateHandler",
        "summary": "Update customer",
        "description": "Changes a customer. `email` is fixed and refused here; a `password` in the body replaces the customer's password and signs them out of every session they have on the website.",
        "tags": [
          "Customer"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `customer`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/dashboard": {
      "get": {
        "operationId": "dashboardGetHandler",
        "summary": "Get dashboard",
        "description": "Reads the dashboard of one website. A website whose dashboard nobody has arranged yet gets the platform's default layout back rather than a 404 \u2014 there is exactly one dashboard per website and it always exists, implicitly.\n\nThat default answer carries `is_default: true` and **no `etag` and no timestamps**: nothing has been stored, so there is nothing to be a version of. Reading it stores nothing either, so a site that never touches its dashboard costs no document and gains every tile a later release adds to the default.",
        "tags": [
          "Dashboard"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dashboard"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "dashboardUpdateHandler",
        "summary": "Update dashboard",
        "description": "Saves an arrangement. Send `widgets` whole \u2014 the layout is replaced, not merged tile by tile, because a tile moved out of the way and a tile deleted are indistinguishable in a per-field merge.\n\nSend the `etag` you read in `If-Match` and a write that lost a race is refused with ABORTED instead of overwriting somebody else's arrangement; the refusal carries the current dashboard, so a builder can show what it would have overwritten. The first write of a never-arranged dashboard sends none \u2014 there is no version yet.\n\nThe whole layout is checked, and every refusal names the tile: a `type` that is not in `dashboard_widget_types`, a `widget_id` used twice, geometry outside the 12 columns or outside the type's own `min_size`/`max_size`, two tiles covering each other, more than 24 tiles, a second copy of a type that allows only one, and a setting the type does not declare or a value it does not allow.",
        "tags": [
          "Dashboard"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dashboard"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DashboardUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/dashboard:reset": {
      "post": {
        "operationId": "dashboardResetHandler",
        "summary": "Reset (dashboard)",
        "description": "Throws the arrangement away and puts the platform's default layout back. It answers exactly what a read of a never-arranged dashboard answers, `is_default: true` included, because that is what the website now has.\n\nThe default is composed fresh from the catalogue rather than stored, so a dashboard reset today and a website created tomorrow look the same \u2014 and both pick up a tile a later release adds. Safe to repeat: resetting an already default dashboard changes nothing.",
        "tags": [
          "Dashboard"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The dashboard singleton (\u00a73.38) as it stands after the reset \u2014 the platform\u2019s default layout, so `is_default` is `true` and there is neither an `etag` nor a timestamp on it: nothing is stored. `widgets` is the same array a Get of a never-arranged dashboard answers."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:reset`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_ai_policy": {
      "get": {
        "operationId": "editorialAiPolicyGetHandler",
        "summary": "Get editorial_ai_policy",
        "description": "Reads how the desk produces content by itself: which agents write, review, translate, propose topics and draw the cover, what the site is about, how long an article should be, what it must not say, which views take a translation, and whether an article that passed review may go live on its own. A website that has never configured it gets the defaults back \u2014 no agents, 1000 words, a passing score of 80, twenty runs a day, no unattended publishing, no automatic topics \u2014 rather than a 404: there is exactly one policy per website and it always exists.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialAiPolicy"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "editorialAiPolicyUpdateHandler",
        "summary": "Update editorial_ai_policy",
        "description": "Changes the policy. Validation runs on the merged document: the ranges, `auto_publish` needing a reviewer, the two image agents set together or not at all, `topic_backlog_min` needing a topic agent, `translate_view_ids` naming this website's views, and \u2014 for every agent named \u2014 that it exists in this website's account, is switched on, runs, and meets its role's contract (a JSON agent whose `output_schema` equals the platform template's and whose instruction declares the variables the desk fills; an `IMAGE` agent for the cover). A refusal is INVALID_ARGUMENT on the field that names the agent, with the reason in words. Nothing is stored unless all of it holds.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialAiPolicy"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialAiPolicyUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_generations": {
      "get": {
        "operationId": "editorialGenerationListHandler",
        "summary": "List editorial_generations",
        "description": "One run of the desk's pipeline. For an article: the text the writer produced, the checks and the review it went through, the translations and the cover that followed, where it was applied, and what it cost. For topics: the batch the strategist proposed and what of it was new. Runs are started by the desk \u2014 when a slot comes within its writing time, or the backlog falls under its floor \u2014 or by a person with Create; they run in the background, so read the run until `state` is final. There is no Update and no Delete: history is not edited, and a new run on a drafted slot is how an article is regenerated \u2014 by parts, and never over a field a person edited. `:cancel` stops a live run, `:retry` resumes a failed one at the step that failed.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `end_time`, `kind`, `pipeline_version`, `slot_id`, `state`, `trigger`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `editorial_generations`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "editorial_generations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EditorialGeneration"
                      },
                      "description": "This page of `editorial_generations`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "editorial_generations"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "editorialGenerationCreateHandler",
        "summary": "Create editorial_generation",
        "description": "Starts a run now, instead of waiting for the desk to reach it. For an article send `kind: ARTICLE` and the `slot_id`; the slot's content mode must be `AI_GENERATED` and the policy must be ready (a writer that meets its contract). The slot moves to `GENERATING` and stays there while the text, the translations and the cover are produced; it is `DRAFTED` when the run is over. `parts` narrows what is produced \u2014 `TEXT`, `TRANSLATIONS`, `IMAGE` \u2014 and a run with explicit parts produces them whatever the text's verdict, where a run without produces the translations and the cover only for an article the checks passed. For topics send `kind: TOPICS` and, optionally, `topic_count`; the policy must name a topic agent, and one `TOPICS` run is live per website at a time. The run answers `QUEUED`: the work happens in the background, so read the run until `state` is final.\n\nOne live run per slot: a second Create answers ALREADY_EXISTS with the run in progress. A slot whose post is live is refused \u2014 live content is changed by a person, never regenerated. Send a `request_id` to make the call safe to repeat: a repeat returns the first run. Runs a person starts do not count against the policy's daily limit.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialGeneration"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialGenerationCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_generations/{editorial_generation_id}": {
      "get": {
        "operationId": "editorialGenerationGetHandler",
        "summary": "Get editorial_generation",
        "description": "One run of the desk's pipeline. For an article: the text the writer produced, the checks and the review it went through, the translations and the cover that followed, where it was applied, and what it cost. For topics: the batch the strategist proposed and what of it was new. Runs are started by the desk \u2014 when a slot comes within its writing time, or the backlog falls under its floor \u2014 or by a person with Create; they run in the background, so read the run until `state` is final. There is no Update and no Delete: history is not edited, and a new run on a drafted slot is how an article is regenerated \u2014 by parts, and never over a field a person edited. `:cancel` stops a live run, `:retry` resumes a failed one at the step that failed.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_generation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_generation`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialGeneration"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_generations/{editorial_generation_id}:cancel": {
      "post": {
        "operationId": "editorialGenerationCancelHandler",
        "summary": "Cancel (editorial_generations)",
        "description": "Stops a live run. Its AI executions are cancelled with it \u2014 one that is mid-call finishes that call and is dropped. A slot whose article was not yet written goes back to `FAILED` with the reason; one whose article was already applied keeps it and is `DRAFTED` with `NEEDS_REVIEW`, since a person now has to look at what the run left unfinished. A run that has already finished answers FAILED_PRECONDITION (`GENERATION_FINISHED`). A cancelled run never restarts by itself: `:retry` it, or create a new one.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_generation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_generation`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:cancel` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:cancel`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_generations/{editorial_generation_id}:retry": {
      "post": {
        "operationId": "editorialGenerationRetryHandler",
        "summary": "Retry (editorial_generations)",
        "description": "Resumes a `FAILED` run at the step that failed, with the same policy snapshot and the same article where one was already written. The failed step retries its own AI execution where the platform still takes it, and gets a new one where it does not. The slot moves back to `GENERATING`. Any other state answers FAILED_PRECONDITION (`GENERATION_NOT_FAILED`); so does a slot that has since moved on to a newer run. A run that failed applying what it had already produced \u2014 the content type refused the article, say \u2014 would fail the same way again, and answers FAILED_PRECONDITION (`STEP_NOT_RETRYABLE`, naming the step): create a new run for the slot instead.",
        "tags": [
          "Editorial AI"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_generation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_generation`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:retry` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:retry`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_plan": {
      "get": {
        "operationId": "editorialPlanGetHandler",
        "summary": "Get editorial_plan",
        "description": "The publication rules of one website's editorial desk: on which days and at what local times posts go out, how far ahead the calendar is filled, how long before its date a slot becomes a draft, and what that draft inherits. There is one per website and it always exists \u2014 a website that has never configured one reads back the defaults, and the first Update is what stores it. What to write about lives in `editorial_topics`, and when each piece goes out in `editorial_slots`.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialPlan"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "editorialPlanUpdateHandler",
        "summary": "Update editorial_plan",
        "description": "Reads the desk's rules. A website that has never configured one gets the defaults back \u2014 the desk switched off, UTC, no schedule, a 30-day horizon and 3 days of writing time \u2014 rather than a 404: there is exactly one plan per website and it always exists, implicitly.\n\n`next_tick_time` says when the desk next looks at this calendar. On an enabled plan a value in the past means the schedule has stalled.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialPlan"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialPlanUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_plan:refill": {
      "post": {
        "operationId": "editorialPlanRefillHandler",
        "summary": "Refill (editorial_plan)",
        "description": "Fills the calendar up to the horizon now, instead of waiting for the desk to get to it. Slots are created on every scheduled moment that has none, taking topics off the backlog in priority order; a moment that already has a slot is left alone, including one that was skipped.\n\nSafe to repeat \u2014 running it twice over unchanged data creates nothing. It answers with the plan; what it actually created is in `editorial_slots`. If the backlog runs dry the calendar is simply left part-filled, which is a state to show rather than an error.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:refill` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:refill`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_slots": {
      "get": {
        "operationId": "editorialSlotListHandler",
        "summary": "List editorial_slots",
        "description": "One cell of the content calendar: a moment, the topic that fills it, and the content it produced. A slot is created by the desk from the plan's schedule, or by hand for a date you want yourself. Its moment is unique, which is how a date you chose is never overwritten \u2014 the desk simply never plans on a taken moment. `:skip` drops the date and returns its topic to the backlog, `:materialize` prepares the draft now rather than waiting, and `:publish` makes that draft live.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `scheduled_time asc`. Sortable: `scheduled_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `origin`, `review_verdict`, `scheduled_time`, `status`, `target_id`, `target_type`, `title`, `topic_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `editorial_slots`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "editorial_slots": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EditorialSlot"
                      },
                      "description": "This page of `editorial_slots`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "editorial_slots"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "editorialSlotCreateHandler",
        "summary": "Create editorial_slot",
        "description": "Puts your own piece on a date, instead of waiting for the desk to plan one. Send at least a `scheduled_time`; name a `topic_id` to take an idea off the backlog, or just a `title` to schedule something that was never on it.\n\nA moment carries one slot, so a date that already has one answers ALREADY_EXISTS \u2014 edit the slot that is there rather than adding a second. A slot created here belongs to you from then on: the desk never plans over it and never changes it.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialSlot"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialSlotCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_slots/{editorial_slot_id}": {
      "delete": {
        "operationId": "editorialSlotDeleteHandler",
        "summary": "Delete editorial_slot",
        "description": "Removes the date from the calendar. Its topic goes back to the backlog, and any draft it already produced is left alone \u2014 that is a post with a life of its own, and dropping a calendar cell is not a reason to delete somebody's article.\n\nDeleting frees the moment, so the desk may plan something else there. To keep a date deliberately empty, use `:skip` instead.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_slot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_slot`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "editorialSlotGetHandler",
        "summary": "Get editorial_slot",
        "description": "One cell of the content calendar: a moment, the topic that fills it, and the content it produced. A slot is created by the desk from the plan's schedule, or by hand for a date you want yourself. Its moment is unique, which is how a date you chose is never overwritten \u2014 the desk simply never plans on a taken moment. `:skip` drops the date and returns its topic to the backlog, `:materialize` prepares the draft now rather than waiting, and `:publish` makes that draft live.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_slot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_slot`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialSlot"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "editorialSlotUpdateHandler",
        "summary": "Update editorial_slot",
        "description": "Moves a slot, or changes what fills it: `scheduled_time` to publish on another date, `topic_id` to swap the idea, `title` to reword the headline the calendar shows. There is no separate reschedule call \u2014 moving a slot is writing its time.\n\nAny edit here hands the slot to you permanently: the desk stops planning it and will not change it again. Swapping the topic returns the previous one to the backlog and takes the new one out of it.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_slot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_slot`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialSlot"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialSlotUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_slots/{editorial_slot_id}:materialize": {
      "post": {
        "operationId": "editorialSlotMaterializeHandler",
        "summary": "Materialize (editorial_slots)",
        "description": "Prepares this slot's draft now, rather than waiting until its date comes near. The draft is created switched off, dated at the slot's moment, with the topic's note as its teaser and the categories, tags and byline the topic or the plan calls for \u2014 so whoever writes it opens a post that already knows what it is for.\n\nSafe to repeat: a slot that already has content answers with the same content instead of making a second copy. It never publishes anything \u2014 that is `:publish`.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_slot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_slot`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:materialize` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:materialize`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_slots/{editorial_slot_id}:publish": {
      "post": {
        "operationId": "editorialSlotPublishHandler",
        "summary": "Publish (editorial_slots)",
        "description": "Makes this slot's draft live. The date was already set when the draft was prepared, so this only flips it on; the slot reaches its published state and its topic is marked used.\n\nNothing publishes on its own \u2014 an article the platform wrote nothing into going out unread is a defect, not a feature \u2014 so this call is the only way a planned piece becomes visible.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_slot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_slot`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:publish` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:publish`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_slots/{editorial_slot_id}:skip": {
      "post": {
        "operationId": "editorialSlotSkipHandler",
        "summary": "Skip (editorial_slots)",
        "description": "Drops this date without giving it up: the slot stays on the calendar as skipped, its topic returns to the backlog, and \u2014 because the moment is still taken \u2014 the desk will not quietly plan something else there. That is the difference from Delete, and it is how \u00abnot this week\u00bb survives the next time the calendar is filled.\n\nA slot whose post is already published cannot be skipped.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_slot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_slot`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:skip` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:skip`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_topics": {
      "get": {
        "operationId": "editorialTopicListHandler",
        "summary": "List editorial_topics",
        "description": "One item of the backlog: something this website intends to write about. A topic outlives the article it becomes \u2014 it records which slot consumed it, and one that was turned down stays turned down instead of resurfacing the next time the calendar is filled. `:batch_create` adds a whole list in one call, `:reject` and `:restore` move it in and out of the backlog, and `:accept` takes in an idea the desk's AI proposed.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `priority`, `title`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `author_id`, `category_ids`, `create_time`, `keywords`, `origin`, `priority`, `slot_id`, `status`, `tag_ids`, `title`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `editorial_topics`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "editorial_topics": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EditorialTopic"
                      },
                      "description": "This page of `editorial_topics`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "editorial_topics"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "editorialTopicCreateHandler",
        "summary": "Create editorial_topic",
        "description": "One item of the backlog: something this website intends to write about. A topic outlives the article it becomes \u2014 it records which slot consumed it, and one that was turned down stays turned down instead of resurfacing the next time the calendar is filled. `:batch_create` adds a whole list in one call, `:reject` and `:restore` move it in and out of the backlog, and `:accept` takes in an idea the desk's AI proposed.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialTopic"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialTopicCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_topics/{editorial_topic_id}": {
      "delete": {
        "operationId": "editorialTopicDeleteHandler",
        "summary": "Delete editorial_topic",
        "description": "Removes a topic from the backlog for good. A topic a calendar slot is holding cannot be deleted \u2014 skip that slot first, which returns the topic to the backlog. Nothing cascades in either direction: deleting a topic never removes a slot, and deleting a slot never removes a topic. To take an idea off the list while keeping the record of it, use `:reject`.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_topic_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_topic`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "editorialTopicGetHandler",
        "summary": "Get editorial_topic",
        "description": "One item of the backlog: something this website intends to write about. A topic outlives the article it becomes \u2014 it records which slot consumed it, and one that was turned down stays turned down instead of resurfacing the next time the calendar is filled. `:batch_create` adds a whole list in one call, `:reject` and `:restore` move it in and out of the backlog, and `:accept` takes in an idea the desk's AI proposed.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_topic_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_topic`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialTopic"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "editorialTopicUpdateHandler",
        "summary": "Update editorial_topic",
        "description": "One item of the backlog: something this website intends to write about. A topic outlives the article it becomes \u2014 it records which slot consumed it, and one that was turned down stays turned down instead of resurfacing the next time the calendar is filled. `:batch_create` adds a whole list in one call, `:reject` and `:restore` move it in and out of the backlog, and `:accept` takes in an idea the desk's AI proposed.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_topic_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_topic`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditorialTopic"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditorialTopicUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_topics/{editorial_topic_id}:accept": {
      "post": {
        "operationId": "editorialTopicAcceptHandler",
        "summary": "Accept (editorial_topics)",
        "description": "Takes a topic the desk's AI proposed into the backlog, where the calendar can plan it. A proposed topic sits outside the calendar until somebody accepts it \u2014 that is the whole point of the approval step \u2014 and `:reject` is the other answer. Accepting a topic that is already a candidate is not an error; anything else answers FAILED_PRECONDITION.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_topic_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_topic`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:accept` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:accept`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_topics/{editorial_topic_id}:reject": {
      "post": {
        "operationId": "editorialTopicRejectHandler",
        "summary": "Reject (editorial_topics)",
        "description": "Turns a topic down: it stays on record but stops being offered when the calendar is filled. This is the point of keeping the backlog separate from the articles \u2014 a rejected idea does not resurface next month because nobody remembered rejecting it.\n\nOnly a topic still waiting in the backlog can be rejected; if a slot is already holding it, skip that slot first. Rejecting an already rejected topic is not an error.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_topic_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_topic`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:reject` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:reject`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_topics/{editorial_topic_id}:restore": {
      "post": {
        "operationId": "editorialTopicRestoreHandler",
        "summary": "Restore (editorial_topics)",
        "description": "Puts a rejected topic back in the backlog, where the calendar can pick it up again. The counterpart of `:reject`, and only valid on a topic that was rejected.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "editorial_topic_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `editorial_topic`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:restore` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:restore`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/editorial_topics:batch_create": {
      "post": {
        "operationId": "editorialTopicBatchCreateHandler",
        "summary": "Batch create (editorial_topics)",
        "description": "Adds a whole list of topics in one call \u2014 the shape a \u00abone idea per line\u00bb box in an editor should send instead of a burst of single Creates. Send them under `editorial_topics`, exactly as each would be sent on its own.\n\nAtomic: if any entry is rejected, nothing is written. Every topic arrives in the backlog as a candidate, in the order given.",
        "tags": [
          "Editorial"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:batch_create` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:batch_create`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/email_templates": {
      "get": {
        "operationId": "emailTemplateListHandler",
        "summary": "List email_templates",
        "description": "The text of one kind of email a website sends: a subject and a plain-text body with `{{placeholders}}`, written in the website's default language. The platform creates one template of each kind for every website, marked `is_default`, and a website may add its own. What another view says instead lives in the template's `views` overlays, and a field a view does not override is sent as written here.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `display_name asc`. Sortable: `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `display_name`, `is_default`, `kind`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `email_templates`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "email_templates": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmailTemplate"
                      },
                      "description": "This page of `email_templates`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "email_templates"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "emailTemplateCreateHandler",
        "summary": "Create email_template",
        "description": "Adds a template of your own beside the one the platform created for its kind \u2014 a second wording to switch the website to, for instance. `kind` is required and must be a kind of email the platform sends; an unknown one is INVALID_ARGUMENT naming the kinds there are. A template created here is never the default of its kind: `is_default` is the platform's to set.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailTemplate"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailTemplateCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/email_templates/{email_template_id}": {
      "delete": {
        "operationId": "emailTemplateDeleteHandler",
        "summary": "Delete email_template",
        "description": "Removes a template together with its per-view overlays. The default template of a kind cannot be deleted \u2014 every email of that kind falls back to it \u2014 and answers FAILED_PRECONDITION; edit its text instead. An email that was set to send from a deleted template is sent from the default of its kind.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `email_template`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "emailTemplateGetHandler",
        "summary": "Get email_template",
        "description": "The text of one kind of email a website sends: a subject and a plain-text body with `{{placeholders}}`, written in the website's default language. The platform creates one template of each kind for every website, marked `is_default`, and a website may add its own. What another view says instead lives in the template's `views` overlays, and a field a view does not override is sent as written here.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `email_template`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailTemplate"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "emailTemplateUpdateHandler",
        "summary": "Update email_template",
        "description": "The text of one kind of email a website sends: a subject and a plain-text body with `{{placeholders}}`, written in the website's default language. The platform creates one template of each kind for every website, marked `is_default`, and a website may add its own. What another view says instead lives in the template's `views` overlays, and a field a view does not override is sent as written here.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `email_template`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailTemplate"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailTemplateUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/email_templates/{email_template_id}/views": {
      "get": {
        "operationId": "emailTemplateViewListHandler",
        "summary": "List views",
        "description": "What one view's email says instead of the template: its subject and text in that view's language. It works like every other overlay \u2014 optional fields, a fallback to the template, and `overridden` deciding which of them this view claims \u2014 with one addition: an Update of an overlay that does not exist yet creates it, so saving a view's text is one call whether or not it had one.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The template this overlay belongs to. Fixed by the URL."
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmailTemplateView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "emailTemplateViewCreateHandler",
        "summary": "Create view",
        "description": "Gives a view its own subject and text for this template. The overlay is named after its view: pass the view's id as `?id=`. A view that already has one answers ALREADY_EXISTS \u2014 update it instead, or skip this call altogether: an Update creates a missing overlay.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The template this overlay belongs to. Fixed by the URL."
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailTemplateView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailTemplateViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/email_templates/{email_template_id}/views/{view_id}": {
      "delete": {
        "operationId": "emailTemplateViewDeleteHandler",
        "summary": "Delete view",
        "description": "Drops this view's own text: its emails go back to the template's, along the view's fallback chain.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The template this overlay belongs to. Fixed by the URL."
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "emailTemplateViewGetHandler",
        "summary": "Get view",
        "description": "What one view's email says instead of the template: its subject and text in that view's language. It works like every other overlay \u2014 optional fields, a fallback to the template, and `overridden` deciding which of them this view claims \u2014 with one addition: an Update of an overlay that does not exist yet creates it, so saving a view's text is one call whether or not it had one.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The template this overlay belongs to. Fixed by the URL."
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailTemplateView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "emailTemplateViewUpdateHandler",
        "summary": "Update view",
        "description": "Writes what this view's email says. If the view has no overlay for the template yet, this creates it, so saving a view's text is the same call either way. Only the fields named in `overridden` are sent in this view \u2014 the others fall back to the template. The view itself must exist on the website; `If-Match` on an overlay that does not exist yet is ABORTED.",
        "tags": [
          "Email Template"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "email_template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The template this overlay belongs to. Fixed by the URL."
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailTemplateView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailTemplateViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/media": {
      "get": {
        "operationId": "mediaListHandler",
        "summary": "List media",
        "description": "A file in the website's media library. Create is a `multipart/form-data` upload \u2014 everything but `alt_text`, `title` and `folder_id` is read off the file itself \u2014 and the bytes come back from `GET /engine-api/v1/websites/{website_id}/media/{id}`, which resizes and re-encodes on the fly \u2014 the same URL a rendered page asks for.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `create_time`, `filename`, `folder_id`, `is_image`, `mime_type`, `original_filename`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `alt_text`, `create_time`, `filename`, `folder_id`, `is_image`, `mime_type`, `original_filename`, `title`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `media`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "media": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Media"
                      },
                      "description": "This page of `media`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "media"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "mediaUploadHandler",
        "summary": "Create media",
        "description": "A file in the website's media library. Create is a `multipart/form-data` upload \u2014 everything but `alt_text`, `title` and `folder_id` is read off the file itself \u2014 and the bytes come back from `GET /engine-api/v1/websites/{website_id}/media/{id}`, which resizes and re-encodes on the fly \u2014 the same URL a rendered page asks for.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "description": "The uploaded file plus the resource fields."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/media/{id}": {
      "delete": {
        "operationId": "mediaDeleteHandler",
        "summary": "Delete media",
        "description": "A file in the website's media library. Create is a `multipart/form-data` upload \u2014 everything but `alt_text`, `title` and `folder_id` is read off the file itself \u2014 and the bytes come back from `GET /engine-api/v1/websites/{website_id}/media/{id}`, which resizes and re-encodes on the fly \u2014 the same URL a rendered page asks for.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "tenantAdminMediaGetHandler",
        "summary": "Get media",
        "description": "A file in the website's media library. Create is a `multipart/form-data` upload \u2014 everything but `alt_text`, `title` and `folder_id` is read off the file itself \u2014 and the bytes come back from `GET /engine-api/v1/websites/{website_id}/media/{id}`, which resizes and re-encodes on the fly \u2014 the same URL a rendered page asks for.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "mediaUpdateHandler",
        "summary": "Update media",
        "description": "A file in the website's media library. Create is a `multipart/form-data` upload \u2014 everything but `alt_text`, `title` and `folder_id` is read off the file itself \u2014 and the bytes come back from `GET /engine-api/v1/websites/{website_id}/media/{id}`, which resizes and re-encodes on the fly \u2014 the same URL a rendered page asks for.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MediaUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/media_folders": {
      "get": {
        "operationId": "mediaFolderListHandler",
        "summary": "List media_folders",
        "description": "A folder of the media library. Folders are a tree: `parent_id` names the one above, `path`, `level` and `sort_order` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. A file's folder is the `folder_id` on the file itself.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `path asc`. Sortable: `display_name`, `level`, `parent_id`, `path`, `sort_order`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `display_name`, `level`, `parent_id`, `path`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `media_folders`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "media_folders": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MediaFolder"
                      },
                      "description": "This page of `media_folders`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "media_folders"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "mediaFolderCreateHandler",
        "summary": "Create media_folder",
        "description": "A folder of the media library. Folders are a tree: `parent_id` names the one above, `path`, `level` and `sort_order` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. A file's folder is the `folder_id` on the file itself.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaFolder"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MediaFolderCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/media_folders/{id}": {
      "delete": {
        "operationId": "mediaFolderDeleteHandler",
        "summary": "Delete media_folder",
        "description": "A folder of the media library. Folders are a tree: `parent_id` names the one above, `path`, `level` and `sort_order` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. A file's folder is the `folder_id` on the file itself.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "mediaFolderGetHandler",
        "summary": "Get media_folder",
        "description": "A folder of the media library. Folders are a tree: `parent_id` names the one above, `path`, `level` and `sort_order` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. A file's folder is the `folder_id` on the file itself.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaFolder"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "mediaFolderUpdateHandler",
        "summary": "Update media_folder",
        "description": "A folder of the media library. Folders are a tree: `parent_id` names the one above, `path`, `level` and `sort_order` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. A file's folder is the `folder_id` on the file itself.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaFolder"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MediaFolderUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/media_folders/{id}:move": {
      "post": {
        "operationId": "mediaFolderMoveHandler",
        "summary": "Move (media_folders)",
        "description": "Moves a folder inside the library's tree. Send `{\"parent_id\": ..., \"after_id\": ...}`: `parent_id` absent or null means the root, `after_id` absent or null means first among its new siblings. The move is what rewrites `path`, `level` and `sort_order`, which is why `parent_id` is immutable on Update.",
        "tags": [
          "Media"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the `media_folders` resource this URL addresses.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:move` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:move`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus": {
      "get": {
        "operationId": "menuListMenusHandler",
        "summary": "List menus",
        "description": "A named navigation menu of the website \u2014 the container its items hang off. A theme points at one by `code`; the links themselves are the `items` collection under it.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `code`, `create_time`, `display_name`, `is_active`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `code`, `create_time`, `display_name`, `is_active`, `view_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `menus`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "menus": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Menu"
                      },
                      "description": "This page of `menus`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "menus"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "menuCreateMenuHandler",
        "summary": "Create menu",
        "description": "A named navigation menu of the website \u2014 the container its items hang off. A theme points at one by `code`; the links themselves are the `items` collection under it.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus/{id}": {
      "delete": {
        "operationId": "menuDeleteMenuHandler",
        "summary": "Delete menu",
        "description": "A named navigation menu of the website \u2014 the container its items hang off. A theme points at one by `code`; the links themselves are the `items` collection under it.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "menuGetMenuHandler",
        "summary": "Get menu",
        "description": "A named navigation menu of the website \u2014 the container its items hang off. A theme points at one by `code`; the links themselves are the `items` collection under it.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "menuUpdateMenuHandler",
        "summary": "Update menu",
        "description": "A named navigation menu of the website \u2014 the container its items hang off. A theme points at one by `code`; the links themselves are the `items` collection under it.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus/{menu_id}/items": {
      "get": {
        "operationId": "menuItemListHandler",
        "summary": "List items",
        "description": "One entry of a menu. What it points at is `type`, and `type` decides which of the target fields is read \u2014 a link to a page carries `cms_page_id`, not a URL, so the menu survives the page being renamed or translated. Items nest: `parent_id` is set on create, and the shape and the order are changed with `:move` afterwards.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The menu this item belongs to. Fixed by the URL."
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `sort_order asc`. Sortable: `create_time`, `sort_order`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `enabled`, `parent_id`, `type`, `view_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `items`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MenuItem"
                      },
                      "description": "This page of `items`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "menuItemCreateHandler",
        "summary": "Create item",
        "description": "One entry of a menu. What it points at is `type`, and `type` decides which of the target fields is read \u2014 a link to a page carries `cms_page_id`, not a URL, so the menu survives the page being renamed or translated. Items nest: `parent_id` is set on create, and the shape and the order are changed with `:move` afterwards.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The menu this item belongs to. Fixed by the URL."
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItem"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuItemCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus/{menu_id}/items/{id}": {
      "delete": {
        "operationId": "menuItemDeleteHandler",
        "summary": "Delete item",
        "description": "One entry of a menu. What it points at is `type`, and `type` decides which of the target fields is read \u2014 a link to a page carries `cms_page_id`, not a URL, so the menu survives the page being renamed or translated. Items nest: `parent_id` is set on create, and the shape and the order are changed with `:move` afterwards.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The menu this item belongs to. Fixed by the URL."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "menuItemGetHandler",
        "summary": "Get item",
        "description": "One entry of a menu. What it points at is `type`, and `type` decides which of the target fields is read \u2014 a link to a page carries `cms_page_id`, not a URL, so the menu survives the page being renamed or translated. Items nest: `parent_id` is set on create, and the shape and the order are changed with `:move` afterwards.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The menu this item belongs to. Fixed by the URL."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItem"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "menuItemUpdateHandler",
        "summary": "Update item",
        "description": "One entry of a menu. What it points at is `type`, and `type` decides which of the target fields is read \u2014 a link to a page carries `cms_page_id`, not a URL, so the menu survives the page being renamed or translated. Items nest: `parent_id` is set on create, and the shape and the order are changed with `:move` afterwards.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The menu this item belongs to. Fixed by the URL."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItem"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuItemUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus/{menu_id}/items/{id}:move": {
      "post": {
        "operationId": "menuItemMoveHandler",
        "summary": "Move (items)",
        "description": "Re-nests or reorders one menu item. Send `{\"parent_id\": ..., \"after_id\": ...}`: `parent_id` absent or null means the top level, `after_id` absent or null means first among its new siblings. This is the only call that may change an item's place \u2014 `parent_id`, `path`, `level` and `sort_order` are all rejected on Update, because moving is what recomputes them.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `menu`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the `items` resource this URL addresses.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:move` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:move`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus/{menu_id}/items/{item_id}/views": {
      "get": {
        "operationId": "menuItemViewListHandler",
        "summary": "List views",
        "description": "What one view says instead of the master menu item: its text, its URL, its raw markup and whether it is shown at all. What the item points at and where it sits in the menu are not overridable.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `menu`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `item`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: none \u2014 this collection serves its documented order only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: none. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MenuItemView"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "menuItemViewCreateHandler",
        "summary": "Create view",
        "description": "What one view says instead of the master menu item: its text, its URL, its raw markup and whether it is shown at all. What the item points at and where it sits in the menu are not overridable.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `menu`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `item`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItemView"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuItemViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/menus/{menu_id}/items/{item_id}/views/{view_id}": {
      "delete": {
        "operationId": "menuItemViewDeleteHandler",
        "summary": "Delete view",
        "description": "What one view says instead of the master menu item: its text, its URL, its raw markup and whether it is shown at all. What the item points at and where it sits in the menu are not overridable.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `menu`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `item`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "menuItemViewGetHandler",
        "summary": "Get view",
        "description": "What one view says instead of the master menu item: its text, its URL, its raw markup and whether it is shown at all. What the item points at and where it sits in the menu are not overridable.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `menu`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `item`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItemView"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "menuItemViewUpdateHandler",
        "summary": "Update view",
        "description": "What one view says instead of the master menu item: its text, its URL, its raw markup and whether it is shown at all. What the item points at and where it sits in the menu are not overridable.",
        "tags": [
          "Navigation"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "menu_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `menu`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `item`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this overlay speaks for. Fixed by the URL."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItemView"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuItemViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/operations/{operation_id}": {
      "get": {
        "operationId": "operationGetHandler",
        "summary": "Get operation",
        "description": "Reads one long-running operation (\u00a717). Poll it until `done` is true, then read exactly one of `response` / `error`; `metadata` reports progress while it runs.\n\nThere is no List and no Create: an Operation is minted by the call that starts the work \u2014 the name comes back in that call's `202` \u2014 and a log of every operation a website ever had would be a different resource than this one.",
        "tags": [
          "Operation"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "operation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `operation`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "An Operation (docs/api/standard.md \u00a717): `name`, `done`, `metadata`, and \u2014 when done \u2014 exactly one of `response` / `error`."
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/operations/{operation_id}:cancel": {
      "post": {
        "operationId": "operationCancelHandler",
        "summary": "Cancel (operations)",
        "description": "Asks a running operation to stop. It is a request, not a guarantee: work already committed stays committed, and the operation reaches `done` with `CANCELLED` only if it noticed in time. Cancelling one that has already finished is FAILED_PRECONDITION.",
        "tags": [
          "Operation"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "operation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `operation`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:cancel` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:cancel`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/settings": {
      "get": {
        "operationId": "websiteSettingsListHandler",
        "summary": "List settings",
        "description": "One website-wide setting, addressed by its dotted path. Two things about this collection are worth knowing before you write to it: the id is the path, and there is no Create \u2014 the platform decides which paths exist, so `PATCH` on a path never written before creates it. `:batch_update` writes many at once, which is what a settings screen should send instead of a burst of single writes.",
        "tags": [
          "Website Settings"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `path asc`. Sortable: `create_time`, `path`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `path`, `view_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `settings`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "settings": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Setting"
                      },
                      "description": "This page of `settings`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "settings"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/settings/{path}": {
      "delete": {
        "operationId": "websiteSettingsDeleteHandler",
        "summary": "Delete setting",
        "description": "One website-wide setting, addressed by its dotted path. Two things about this collection are worth knowing before you write to it: the id is the path, and there is no Create \u2014 the platform decides which paths exist, so `PATCH` on a path never written before creates it. `:batch_update` writes many at once, which is what a settings screen should send instead of a burst of single writes.",
        "tags": [
          "Website Settings"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The setting's dotted path, which is also its id \u2014 `general.info.site_name`, `appearance.theme.default_theme`. Which paths exist is decided by the platform, so a write cannot invent one and cannot move one.",
            "example": "general.info.site_name"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "websiteSettingsGetHandler",
        "summary": "Get setting",
        "description": "One website-wide setting, addressed by its dotted path. Two things about this collection are worth knowing before you write to it: the id is the path, and there is no Create \u2014 the platform decides which paths exist, so `PATCH` on a path never written before creates it. `:batch_update` writes many at once, which is what a settings screen should send instead of a burst of single writes.",
        "tags": [
          "Website Settings"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The setting's dotted path, which is also its id \u2014 `general.info.site_name`, `appearance.theme.default_theme`. Which paths exist is decided by the platform, so a write cannot invent one and cannot move one.",
            "example": "general.info.site_name"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Setting"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "websiteSettingsUpdateHandler",
        "summary": "Update setting",
        "description": "One website-wide setting, addressed by its dotted path. Two things about this collection are worth knowing before you write to it: the id is the path, and there is no Create \u2014 the platform decides which paths exist, so `PATCH` on a path never written before creates it. `:batch_update` writes many at once, which is what a settings screen should send instead of a burst of single writes.",
        "tags": [
          "Website Settings"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The setting's dotted path, which is also its id \u2014 `general.info.site_name`, `appearance.theme.default_theme`. Which paths exist is decided by the platform, so a write cannot invent one and cannot move one.",
            "example": "general.info.site_name"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Setting"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettingUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/settings:batch_update": {
      "post": {
        "operationId": "websiteSettingsBatchUpdateHandler",
        "summary": "Batch update (settings)",
        "description": "Writes many settings in one atomic call: every value lands or none does. This is what a settings screen should send instead of a burst of single `PATCH`es \u2014 a half-applied screen is a site configured in a state nobody chose.",
        "tags": [
          "Website Settings"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:batch_update` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:batch_update`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/themes": {
      "get": {
        "operationId": "themeListThemesHandler",
        "summary": "List themes",
        "description": "How the site looks and what furniture it renders: the CSS-variable map, plus the logo, the favicon, the main menu and the footer block the layout pulls in. A website can hold several themes; which one it renders is the `appearance.theme.default_theme` setting, and that setting is view-overridable \u2014 so one language can wear a different theme, and swap its navigation and footer with it.",
        "tags": [
          "Theme"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `code`, `create_time`, `display_name`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `code`, `create_time`, `display_name`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `themes`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "themes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Theme"
                      },
                      "description": "This page of `themes`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "themes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "themeCreateThemeHandler",
        "summary": "Create theme",
        "description": "How the site looks and what furniture it renders: the CSS-variable map, plus the logo, the favicon, the main menu and the footer block the layout pulls in. A website can hold several themes; which one it renders is the `appearance.theme.default_theme` setting, and that setting is view-overridable \u2014 so one language can wear a different theme, and swap its navigation and footer with it.",
        "tags": [
          "Theme"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Theme"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThemeCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/themes/{id}": {
      "delete": {
        "operationId": "themeDeleteThemeHandler",
        "summary": "Delete theme",
        "description": "How the site looks and what furniture it renders: the CSS-variable map, plus the logo, the favicon, the main menu and the footer block the layout pulls in. A website can hold several themes; which one it renders is the `appearance.theme.default_theme` setting, and that setting is view-overridable \u2014 so one language can wear a different theme, and swap its navigation and footer with it.",
        "tags": [
          "Theme"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "themeGetThemeHandler",
        "summary": "Get theme",
        "description": "How the site looks and what furniture it renders: the CSS-variable map, plus the logo, the favicon, the main menu and the footer block the layout pulls in. A website can hold several themes; which one it renders is the `appearance.theme.default_theme` setting, and that setting is view-overridable \u2014 so one language can wear a different theme, and swap its navigation and footer with it.",
        "tags": [
          "Theme"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Theme"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "themeUpdateThemeHandler",
        "summary": "Update theme",
        "description": "How the site looks and what furniture it renders: the CSS-variable map, plus the logo, the favicon, the main menu and the footer block the layout pulls in. A website can hold several themes; which one it renders is the `appearance.theme.default_theme` setting, and that setting is view-overridable \u2014 so one language can wear a different theme, and swap its navigation and footer with it.",
        "tags": [
          "Theme"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Theme"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThemeUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/views": {
      "get": {
        "operationId": "viewListViewsHandler",
        "summary": "List views",
        "description": "One presentation of the website \u2014 in practice, one language: its locale, its URL prefix, its place in the switcher and its fallback. A view is not a copy of the site: content stays one resource and carries a per-view overlay, and settings can be overridden per view. Everything a visitor sees is decided by the view their URL resolved to.",
        "tags": [
          "View"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `create_time desc`. Sortable: `code`, `create_time`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `code`, `create_time`, `fallback_view_id`, `is_active`, `locale`, `path_prefix`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `views`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "views": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/View"
                      },
                      "description": "This page of `views`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "views"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "viewCreateViewHandler",
        "summary": "Create view",
        "description": "One presentation of the website \u2014 in practice, one language: its locale, its URL prefix, its place in the switcher and its fallback. A view is not a copy of the site: content stays one resource and carries a per-view overlay, and settings can be overridden per view. Everything a visitor sees is decided by the view their URL resolved to.",
        "tags": [
          "View"
        ],
        "x-method-kind": "CREATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "201": {
            "description": "The created resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/View"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created resource (D4).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ViewCreate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/views/{id}": {
      "delete": {
        "operationId": "viewDeleteViewHandler",
        "summary": "Delete view",
        "description": "One presentation of the website \u2014 in practice, one language: its locale, its URL prefix, its place in the switcher and its fallback. A view is not a copy of the site: content stays one resource and carries a per-view overlay, and settings can be overridden per view. Everything a visitor sees is decided by the view their URL resolved to.",
        "tags": [
          "View"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "viewGetViewHandler",
        "summary": "Get view",
        "description": "One presentation of the website \u2014 in practice, one language: its locale, its URL prefix, its place in the switcher and its fallback. A view is not a copy of the site: content stays one resource and carries a per-view overlay, and settings can be overridden per view. Everything a visitor sees is decided by the view their URL resolved to.",
        "tags": [
          "View"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/View"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "viewUpdateViewHandler",
        "summary": "Update view",
        "description": "One presentation of the website \u2014 in practice, one language: its locale, its URL prefix, its place in the switcher and its fallback. A view is not a copy of the site: content stays one resource and carries a per-view overlay, and settings can be overridden per view. Everything a visitor sees is decided by the view their URL resolved to.",
        "tags": [
          "View"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform."
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/View"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ViewUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/views/{view_id}/settings": {
      "get": {
        "operationId": "viewSettingsListHandler",
        "summary": "List settings",
        "description": "One setting overridden for one view. Same shape as the website-wide collection and the same upsert rule \u2014 `PATCH` on a path never written for this view creates the override \u2014 with two differences: the path must be one `setting_descriptors` marks `view_overridable`, and deleting the resource removes the override rather than the setting \u2014 the view goes back to the website-wide value.",
        "tags": [
          "View Settings"
        ],
        "x-method-kind": "LIST",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this override belongs to. Fixed by the URL."
          },
          {
            "name": "page_size",
            "in": "query",
            "description": "Rows per page. Over the maximum is clamped, not rejected.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page_token",
            "in": "query",
            "description": "Opaque token from a previous `next_page_token`. A token minted under a different `order_by`/`filter` is rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "in": "query",
            "description": "Rows to skip before the page (AIP-158). `skip + page_size` is capped at 10000; beyond that is OUT_OF_RANGE.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Comma-separated `field [asc|desc]`, at most 3 keys. Default: `path asc`. Sortable: `create_time`, `path`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "AIP-160 subset (\u00a78). Filterable: `create_time`, `path`, `view_id`. A field outside the list is INVALID_ARGUMENT.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of `settings`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "settings": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ViewSetting"
                      },
                      "description": "This page of `settings`, in the requested order."
                    },
                    "next_page_token": {
                      "type": "string",
                      "description": "Opaque. Absent or empty means this was the last page."
                    },
                    "total_size": {
                      "type": "integer",
                      "format": "int64",
                      "description": "Rows in the whole filtered collection, not in this page."
                    }
                  },
                  "required": [
                    "settings"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/views/{view_id}/settings/{path}": {
      "delete": {
        "operationId": "viewSettingsDeleteHandler",
        "summary": "Delete setting",
        "description": "One setting overridden for one view. Same shape as the website-wide collection and the same upsert rule \u2014 `PATCH` on a path never written for this view creates the override \u2014 with two differences: the path must be one `setting_descriptors` marks `view_overridable`, and deleting the resource removes the override rather than the setting \u2014 the view goes back to the website-wide value.",
        "tags": [
          "View Settings"
        ],
        "x-method-kind": "DELETE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this override belongs to. Fixed by the URL."
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The setting's dotted path, which is also its id. Only a path whose `setting_descriptors` entry says `view_overridable` may be written here.",
            "example": "general.info.site_name"
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body (\u00a77)."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "viewSettingsGetHandler",
        "summary": "Get setting",
        "description": "One setting overridden for one view. Same shape as the website-wide collection and the same upsert rule \u2014 `PATCH` on a path never written for this view creates the override \u2014 with two differences: the path must be one `setting_descriptors` marks `view_overridable`, and deleting the resource removes the override rather than the setting \u2014 the view goes back to the website-wide value.",
        "tags": [
          "View Settings"
        ],
        "x-method-kind": "GET",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this override belongs to. Fixed by the URL."
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The setting's dotted path, which is also its id. Only a path whose `setting_descriptors` entry says `view_overridable` may be written here.",
            "example": "general.info.site_name"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "A matching etag answers 304 with no body (\u00a716).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ViewSetting"
                }
              }
            }
          },
          "304": {
            "description": "Not modified."
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "operationId": "viewSettingsUpdateHandler",
        "summary": "Update setting",
        "description": "One setting overridden for one view. Same shape as the website-wide collection and the same upsert rule \u2014 `PATCH` on a path never written for this view creates the override \u2014 with two differences: the path must be one `setting_descriptors` marks `view_overridable`, and deleting the resource removes the override rather than the setting \u2014 the view goes back to the website-wide value.",
        "tags": [
          "View Settings"
        ],
        "x-method-kind": "UPDATE",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The view this override belongs to. Fixed by the URL."
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The setting's dotted path, which is also its id. Only a path whose `setting_descriptors` entry says `view_overridable` may be written here.",
            "example": "general.info.site_name"
          },
          {
            "name": "update_mask",
            "in": "query",
            "description": "Comma-separated field paths to merge. A field named here and sent as `null` is cleared; without the mask a `null` is dropped (\u00a77, \u00a711).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "The etag the client last read. A mismatch is ABORTED (409) with the current resource in the error details (\u00a714).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The updated resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ViewSetting"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_EXISTS, or ABORTED when an `If-Match` etag no longer matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ViewSettingUpdate"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}/views/{view_id}/settings:batch_update": {
      "post": {
        "operationId": "viewSettingsBatchUpdateHandler",
        "summary": "Batch update (settings)",
        "description": "Writes many per-view overrides in one atomic call: every value lands or none does. A path that is not marked `view_overridable` rejects the whole request rather than being skipped.",
        "tags": [
          "View Settings"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          },
          {
            "name": "view_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `view`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:batch_update` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:batch_update`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/tenant-api/v1/websites/{website_id}:reindex_search": {
      "post": {
        "operationId": "searchReindexHandler",
        "summary": "Reindex search (websites)",
        "description": "Rebuilds the website's search index from its current content, across every view. It answers with an Operation to poll (\u00a717), because a full rebuild outlives the request.\n\nOrdinary edits are indexed as they happen \u2014 this is for the cases that are not ordinary: a bulk import, a restored backup, a search that has drifted. There is no query endpoint here: ranked search is served on the site's own domain, to the site's own visitors.",
        "tags": [
          "Search"
        ],
        "x-method-kind": "CUSTOM",
        "parameters": [
          {
            "name": "website_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Id of the parent `website`.",
            "example": "6f3b1c8e2a4d"
          }
        ],
        "responses": {
          "202": {
            "description": "An Operation (\u00a717), when the work outlives the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the Operation.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "200": {
            "description": "The affected resource, or the method\u2019s own response object (\u00a710).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The answer of `:reindex_search` \u2014 the affected resource, or the method\u2019s own response object (\u00a710). A custom method\u2019s answer is not the resource, so it declares no ResourceSpec."
                }
              }
            }
          },
          "400": {
            "description": "INVALID_ARGUMENT, FAILED_PRECONDITION or OUT_OF_RANGE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED \u2014 missing, expired or unparsable credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND \u2014 absent, or present but invisible to this caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL \u2014 carries REQUEST_INFO with the reference id from the log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Arguments of `:reindex_search`. May carry `request_id` (\u00a715) when the method provisions, sends mail or is otherwise not repeatable."
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Status": {
        "type": "object",
        "description": "The error body of every non-2xx response on every surface (\u00a713).",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "description": "The one and only member of an error body \u2014 there is never a partial resource beside it.",
            "required": [
              "code",
              "status",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer",
                "description": "The HTTP status."
              },
              "status": {
                "type": "string",
                "description": "The canonical status.",
                "enum": [
                  "INVALID_ARGUMENT",
                  "FAILED_PRECONDITION",
                  "OUT_OF_RANGE",
                  "UNAUTHENTICATED",
                  "PERMISSION_DENIED",
                  "NOT_FOUND",
                  "ALREADY_EXISTS",
                  "ABORTED",
                  "RESOURCE_EXHAUSTED",
                  "CANCELLED",
                  "INTERNAL",
                  "NOT_IMPLEMENTED",
                  "UNAVAILABLE",
                  "DEADLINE_EXCEEDED"
                ]
              },
              "message": {
                "type": "string",
                "description": "For a developer reading a log. Never internal detail."
              },
              "details": {
                "type": "array",
                "description": "Structured detail, of the closed set of types below.",
                "items": {
                  "type": "object",
                  "required": [
                    "type"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Which kind of detail this is.",
                      "enum": [
                        "BAD_REQUEST",
                        "PRECONDITION_FAILURE",
                        "QUOTA_FAILURE",
                        "RESOURCE_INFO",
                        "RETRY_INFO",
                        "REQUEST_INFO",
                        "LOCALIZED_MESSAGE"
                      ]
                    },
                    "field_violations": {
                      "type": "array",
                      "description": "On a BAD_REQUEST: one entry per field the request got wrong.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "field": {
                            "type": "string",
                            "description": "Field path in the REQUEST body."
                          },
                          "description": {
                            "type": "string",
                            "description": "What is wrong with that field."
                          }
                        }
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "AccountRole": {
        "type": "object",
        "description": "The account's own roles: named sets of grants, defined once and given to members and invitations by name \u2014 `role: accounts/{account}/roles/{role}` \u2014 beside the three roles every account has (`roles`). A member's rights follow the role, so changing its grants changes what every holder may do. Reading the roles takes the `account.access` section; defining, changing and deleting them takes writing it. A role that a member holds or an invitation names is not deleted, and deleting the account deletes its roles.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/roles/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The role's name, as member pickers show it \u2014 unique in the account, surrounding spaces dropped, at most 100 characters. A second role of the same name is ALREADY_EXISTS. The list is ordered by it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Blog writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the role is for, in a sentence a member picker can show next to the choice; at most 1000 characters, empty when there is none.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Writes and publishes blog posts, and uploads their images."
            ]
          },
          "grants": {
            "description": "What the role holds, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. A grant covers the section's whole subtree and brings its `implies` along. Every member holding the role holds exactly these, and a change counts from their next request. Nobody may define a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          },
          "member_count": {
            "type": "integer",
            "format": "int64",
            "description": "How many members of the account hold the role now. A role that a member holds, or that an invitation names, cannot be deleted.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              3
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/roles/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Blog writer",
            "description": "Writes and publishes blog posts, and uploads their images.",
            "grants": [
              {
                "permission": "website.blog.posts",
                "level": "WRITE"
              }
            ],
            "member_count": 3
          }
        ]
      },
      "AccountRoleCreate": {
        "type": "object",
        "description": "The `roles` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The role's name, as member pickers show it \u2014 unique in the account, surrounding spaces dropped, at most 100 characters. A second role of the same name is ALREADY_EXISTS. The list is ordered by it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Blog writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the role is for, in a sentence a member picker can show next to the choice; at most 1000 characters, empty when there is none.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Writes and publishes blog posts, and uploads their images."
            ]
          },
          "grants": {
            "description": "What the role holds, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. A grant covers the section's whole subtree and brings its `implies` along. Every member holding the role holds exactly these, and a change counts from their next request. Nobody may define a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Blog writer"
          }
        ]
      },
      "AccountRoleUpdate": {
        "type": "object",
        "description": "The `roles` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The role's name, as member pickers show it \u2014 unique in the account, surrounding spaces dropped, at most 100 characters. A second role of the same name is ALREADY_EXISTS. The list is ordered by it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Blog writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the role is for, in a sentence a member picker can show next to the choice; at most 1000 characters, empty when there is none.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Writes and publishes blog posts, and uploads their images."
            ]
          },
          "grants": {
            "description": "What the role holds, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. A grant covers the section's whole subtree and brings its `implies` along. Every member holding the role holds exactly these, and a change counts from their next request. Nobody may define a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "examples": [
          {
            "display_name": "Blog writer"
          }
        ]
      },
      "Invitation": {
        "type": "object",
        "description": "An invitation to join the account, mailed to an address with a one-time link. Whoever holds the link reads what it is for with `invitations:inspect` and takes it up with `invitations:accept` \u2014 signed in as the invited address, or as a new user choosing a password. Accepting makes a member with the invitation's `role` and uses the invitation up. Listing, reading, sending and withdrawing invitations take the `account.access` section.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/invitations/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "email": {
            "type": "string",
            "description": "The address the invitation is mailed to, stored lowercase. One pending invitation per address: inviting it again, or inviting a member's address, is ALREADY_EXISTS. The list is ordered by it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "ana@example.com"
            ]
          },
          "role": {
            "type": "string",
            "description": "The role the membership will hold once the invitation is accepted: `roles/admin`, `roles/editor` or `roles/sections` (see `roles`), or one of the account's own, `accounts/{account}/roles/{role}`. Nobody may invite with a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "roles/editor"
            ]
          },
          "grants": {
            "description": "The sections a `roles/sections` invitation grants, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. Empty, and refused when sent, under any other role. Nobody may grant a section they do not hold themselves.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          },
          "inviter": {
            "type": "string",
            "description": "The member who sent the invitation, as `users/{user}`; absent once that user no longer exists.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "users/64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "state": {
            "type": "string",
            "description": "`PENDING` until `expire_time`, then `EXPIRED`: the link no longer works, but the invitation stays listed for 30 days so it can be sent again with `:resend` \u2014 or withdrawn. An accepted invitation is gone.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "PENDING"
            ]
          },
          "expire_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the link stops working: 7 days after the invitation was sent, or sent again.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/invitations/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "email": "ana@example.com",
            "role": "roles/editor",
            "grants": [
              {
                "permission": "website.blog.posts",
                "level": "WRITE"
              }
            ],
            "inviter": "users/64ff1f77aa01b2c3d4e5f607",
            "state": "PENDING",
            "expire_time": "2026-01-15T09:30:00Z"
          }
        ]
      },
      "InvitationCreate": {
        "type": "object",
        "description": "The `invitations` fields a client may set on create.",
        "properties": {
          "email": {
            "type": "string",
            "description": "The address the invitation is mailed to, stored lowercase. One pending invitation per address: inviting it again, or inviting a member's address, is ALREADY_EXISTS. The list is ordered by it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "ana@example.com"
            ]
          },
          "role": {
            "type": "string",
            "description": "The role the membership will hold once the invitation is accepted: `roles/admin`, `roles/editor` or `roles/sections` (see `roles`), or one of the account's own, `accounts/{account}/roles/{role}`. Nobody may invite with a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "roles/editor"
            ]
          },
          "grants": {
            "description": "The sections a `roles/sections` invitation grants, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. Empty, and refused when sent, under any other role. Nobody may grant a section they do not hold themselves.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          },
          "request_id": {
            "type": "string",
            "description": "An idempotency key you choose, at most 64 characters. Creating with a key already used in this account returns the invitation that key created, and mails nothing.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "3f6c1b8e-6b7a-4f0e-9d53-2d8a0c1e7b42"
            ]
          }
        },
        "required": [
          "email",
          "role"
        ],
        "examples": [
          {
            "email": "ana@example.com",
            "role": "roles/editor"
          }
        ]
      },
      "InvitationUpdate": {
        "type": "object",
        "description": "The `invitations` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "email": {
            "type": "string",
            "description": "The address the invitation is mailed to, stored lowercase. One pending invitation per address: inviting it again, or inviting a member's address, is ALREADY_EXISTS. The list is ordered by it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "ana@example.com"
            ]
          },
          "role": {
            "type": "string",
            "description": "The role the membership will hold once the invitation is accepted: `roles/admin`, `roles/editor` or `roles/sections` (see `roles`), or one of the account's own, `accounts/{account}/roles/{role}`. Nobody may invite with a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "roles/editor"
            ]
          },
          "grants": {
            "description": "The sections a `roles/sections` invitation grants, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. Empty, and refused when sent, under any other role. Nobody may grant a section they do not hold themselves.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          },
          "request_id": {
            "type": "string",
            "description": "An idempotency key you choose, at most 64 characters. Creating with a key already used in this account returns the invitation that key created, and mails nothing.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "3f6c1b8e-6b7a-4f0e-9d53-2d8a0c1e7b42"
            ]
          }
        },
        "examples": [
          {
            "email": "ana@example.com",
            "role": "roles/editor"
          }
        ]
      },
      "Member": {
        "type": "object",
        "description": "Who belongs to the account and what each of them may do. Listing the members, reading someone else's membership, changing a role and removing a member take the `account.access` section; every member may read their own membership, `members/{their user id}`, and leave the account by deleting it. The owner is a member too and cannot be removed or leave: ownership is handed over first.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/members/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "user": {
            "type": "string",
            "description": "The member, as `users/{user}` \u2014 the same name the account's `owner` uses. The last segment is also this membership's `id`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "users/64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "email": {
            "type": "string",
            "description": "The member's email address, from their user profile. The list is ordered by it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "ana@example.com"
            ]
          },
          "firstname": {
            "type": "string",
            "description": "The member's first name, from their user profile; absent when they gave none.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Ana"
            ]
          },
          "lastname": {
            "type": "string",
            "description": "The member's last name, from their user profile; absent when they gave none.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Souza"
            ]
          },
          "role": {
            "type": "string",
            "description": "The membership's role: `roles/admin`, `roles/editor` or `roles/sections` (see `roles`), or one of the account's own, `accounts/{account}/roles/{role}` \u2014 never another account's. The owner's membership reads `roles/admin` \u2014 dormant while they own the account, and what they keep after handing it over \u2014 and cannot be changed. Nobody may give a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "roles/sections"
            ]
          },
          "grants": {
            "description": "The sections a `roles/sections` membership holds, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. Empty, and refused when sent, under any other role. Nobody may give a grant they do not hold themselves.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          },
          "is_owner": {
            "type": "boolean",
            "description": "True for the account's one owner, who holds everything whatever the role says. The owner's membership is neither removed nor changed; the account is handed over first (`accounts/{account}:transfer_ownership`).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              false
            ]
          },
          "effective_grants": {
            "description": "What the member actually holds, computed on every read: the role's grants \u2014 or the membership's own \u2014 with `implies` followed, minimal and in the order of `permissions`. The owner's are everything. Sections every member may read are readable whatever this says.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                },
                {
                  "permission": "website.media",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/members/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "user": "users/64ff1f77aa01b2c3d4e5f607",
            "email": "ana@example.com",
            "firstname": "Ana",
            "lastname": "Souza",
            "role": "roles/sections",
            "grants": [
              {
                "permission": "website.blog.posts",
                "level": "WRITE"
              }
            ],
            "is_owner": false,
            "effective_grants": [
              {
                "permission": "website.blog.posts",
                "level": "WRITE"
              },
              {
                "permission": "website.media",
                "level": "WRITE"
              }
            ]
          }
        ]
      },
      "MemberCreate": {
        "type": "object",
        "description": "The `members` fields a client may set on create.",
        "properties": {
          "role": {
            "type": "string",
            "description": "The membership's role: `roles/admin`, `roles/editor` or `roles/sections` (see `roles`), or one of the account's own, `accounts/{account}/roles/{role}` \u2014 never another account's. The owner's membership reads `roles/admin` \u2014 dormant while they own the account, and what they keep after handing it over \u2014 and cannot be changed. Nobody may give a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "roles/sections"
            ]
          },
          "grants": {
            "description": "The sections a `roles/sections` membership holds, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. Empty, and refused when sent, under any other role. Nobody may give a grant they do not hold themselves.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "examples": [
          {
            "role": "roles/sections",
            "grants": [
              {
                "permission": "website.blog.posts",
                "level": "WRITE"
              }
            ]
          }
        ]
      },
      "MemberUpdate": {
        "type": "object",
        "description": "The `members` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "role": {
            "type": "string",
            "description": "The membership's role: `roles/admin`, `roles/editor` or `roles/sections` (see `roles`), or one of the account's own, `accounts/{account}/roles/{role}` \u2014 never another account's. The owner's membership reads `roles/admin` \u2014 dormant while they own the account, and what they keep after handing it over \u2014 and cannot be changed. Nobody may give a role wider than their own: that is PERMISSION_DENIED.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "roles/sections"
            ]
          },
          "grants": {
            "description": "The sections a `roles/sections` membership holds, as `{permission, level}` \u2014 a section `id` from `permissions` and `READ` or `WRITE`. Empty, and refused when sent, under any other role. Nobody may give a grant they do not hold themselves.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "permission": "website.blog.posts",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "examples": [
          {
            "role": "roles/sections",
            "grants": [
              {
                "permission": "website.blog.posts",
                "level": "WRITE"
              }
            ]
          }
        ]
      },
      "Permission": {
        "type": "object",
        "description": "The sections of the product a right can be granted on, as a tree: each has an `id` a grant names (`{permission, level}`, with `level` `READ` or `WRITE` \u2014 writing includes reading), and a grant on a section covers everything under it. Listed in tree order, each section right after its parent. Nothing here is stored or writable: it is the platform's catalogue, and a section a new release adds shows up here \u2014 and in every role that holds its parent \u2014 without anyone editing a role.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "permissions/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "parent": {
            "type": "string",
            "description": "The section this one belongs to, as its resource name. Absent on the two roots \u2014 `account`, everything about the account itself, and `website`, everything inside its websites. A grant on a section covers every section under it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "permissions/website"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The section's name as a person reads it, in English. tenant-admin shows its own translation, looked up by `id`, and falls back to this one.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Media library"
            ]
          },
          "description": {
            "type": "string",
            "description": "What a grant on this section lets a member do, in a sentence or two a role editor can show as help text.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "readable_by_all_members": {
            "type": "boolean",
            "description": "True where every member of the account may read without any grant \u2014 everything inside the websites, and the account's settings and projects \u2014 so that every picker works under every role. On such a section a `READ` grant only decides whether it shows in the menu; changing anything still takes `WRITE`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              true
            ]
          },
          "implies": {
            "description": "The grants holding this section brings along, as `{when, permission, level}`: whoever holds `when` (`READ` or `WRITE`) on this section \u2014 or on a section above it \u2014 holds `level` on `permission` too. It is what keeps a narrow role usable: writing a theme uploads its logo, so it brings writing to the media library with it. Empty on most sections.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                {
                  "when": "WRITE",
                  "permission": "website.media",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "permissions/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "parent": "permissions/website",
            "display_name": "Media library",
            "description": "string",
            "readable_by_all_members": true,
            "implies": [
              {
                "when": "WRITE",
                "permission": "website.media",
                "level": "WRITE"
              }
            ]
          }
        ]
      },
      "PermissionCreate": {
        "type": "object",
        "description": "The `permissions` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "PermissionUpdate": {
        "type": "object",
        "description": "The `permissions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "Role": {
        "type": "object",
        "description": "The three roles every account has without defining them, which a membership names in its `role`: `roles/admin` \u2014 everything in the account, access management included, but not the owner's own acts; `roles/editor` \u2014 everything but access management; and `roles/sections` \u2014 only the sections its membership grants. The account's owner holds everything whatever the role says, and is the only one who may delete the account. Website content stays readable under every role, so pickers work; changing it takes a grant. An account defines roles of its own under `accounts/{account}/roles`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "roles/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The role's name as a person reads it, in English.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Editor"
            ]
          },
          "description": {
            "type": "string",
            "description": "What a member with this role may do, in a sentence or two a member picker can show next to the choice.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "grants": {
            "description": "What the role holds, as `{permission, level}` \u2014 computed from `permissions` on every read rather than stored, so a section a new release adds is in `roles/admin` and `roles/editor` the day it ships. Minimal: no grant that another one already covers, and `implies` already followed. Empty for `roles/sections`, whose grants are each membership's own.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                {
                  "permission": "account.settings",
                  "level": "WRITE"
                },
                {
                  "permission": "website",
                  "level": "WRITE"
                }
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "roles/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Editor",
            "description": "string",
            "grants": [
              {
                "permission": "account.settings",
                "level": "WRITE"
              },
              {
                "permission": "website",
                "level": "WRITE"
              }
            ]
          }
        ]
      },
      "RoleCreate": {
        "type": "object",
        "description": "The `roles` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "RoleUpdate": {
        "type": "object",
        "description": "The `roles` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "Account": {
        "type": "object",
        "description": "The top of the ownership tree: an account owns projects, a project owns websites, and a user reaches a website only through a membership in its account. The list is already scoped to the caller's own memberships, so there is nothing to filter by hand \u2014 and for the same reason its `total_size` counts what the caller can see, not what the platform holds.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The account's label, as the admin shows it in the account switcher.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Northwind Trading"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the account is in use. An inactive one is invisible on this surface: the list skips it and a read answers NOT_FOUND.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "owner": {
            "type": "string",
            "description": "The member who owns the account, as `users/{user}`: whoever created it, or the first member of an account made for them. An account has exactly one owner; neither Create nor Update sets it, and only the owner moves it, with `:transfer_ownership`. The owner may do everything in the account whatever their role says, is the only member who may delete it or hand it over, and can be neither removed from it nor leave it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "users/64ff1f77aa01b2c3d4e5f607"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Northwind Trading",
            "is_active": true,
            "owner": "users/64ff1f77aa01b2c3d4e5f607"
          }
        ]
      },
      "AccountCreate": {
        "type": "object",
        "description": "The `accounts` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The account's label, as the admin shows it in the account switcher.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Northwind Trading"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the account is in use. An inactive one is invisible on this surface: the list skips it and a read answers NOT_FOUND.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          }
        },
        "required": [
          "display_name",
          "is_active"
        ],
        "examples": [
          {
            "display_name": "Northwind Trading",
            "is_active": true
          }
        ]
      },
      "AccountUpdate": {
        "type": "object",
        "description": "The `accounts` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The account's label, as the admin shows it in the account switcher.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Northwind Trading"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the account is in use. An inactive one is invisible on this surface: the list skips it and a read answers NOT_FOUND.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          }
        },
        "examples": [
          {
            "display_name": "Northwind Trading",
            "is_active": true
          }
        ]
      },
      "AiBilling": {
        "type": "object",
        "description": "The account's AI balance, what it has spent today and this month, and the limits on that spending. Runs on the platform's key are paid from the balance and checked against the limits before they start; runs on the account's own provider key are not.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_billing"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "balance": {
            "description": "The AI balance as Money: what runs on the platform's key (`MANAGED`) are paid from. It is the balance after the latest row of `ai_transactions`, and it can be negative when runs started together spent past it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "currency_code": {
            "type": "string",
            "description": "The currency the balance, the limits and every charge are kept in (ISO 4217).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "USD"
            ]
          },
          "monthly_limit": {
            "description": "The most the account may spend on the platform's key in a calendar month (UTC), as Money. A run that could take the month past it is refused before it starts. Leave it unset for no limit.",
            "x-field-behavior": "OPTIONAL"
          },
          "daily_limit": {
            "description": "The most the account may spend on the platform's key in a calendar day (UTC), as Money. A run that could take the day past it is refused before it starts.",
            "x-field-behavior": "OPTIONAL"
          },
          "max_concurrent_executions": {
            "type": "integer",
            "format": "int64",
            "description": "The most runs the account may have queued or running at once, on any connection. A run created past it is refused with `CONCURRENCY_LIMIT_REACHED`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              5
            ]
          },
          "platform_monthly_limit": {
            "description": "The platform's monthly ceiling for this account, as Money. It applies over `monthly_limit`: the lower of the two is the one in force.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "platform_daily_limit": {
            "description": "The platform's daily ceiling for this account, as Money, in force over `daily_limit`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "platform_max_concurrent_executions": {
            "type": "integer",
            "format": "int64",
            "description": "The platform's ceiling on runs queued or running at once for this account, in force over `max_concurrent_executions`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "spend_today": {
            "description": "What runs on the platform's key were charged today (UTC), as Money \u2014 the figure `daily_limit` is measured against.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "spend_mtd": {
            "description": "What runs on the platform's key were charged this calendar month so far (UTC), as Money \u2014 the figure `monthly_limit` is measured against.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          }
        },
        "required": [
          "name"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_billing",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "balance": {},
            "currency_code": "USD",
            "monthly_limit": {},
            "daily_limit": {},
            "max_concurrent_executions": 5,
            "platform_monthly_limit": {},
            "platform_daily_limit": {},
            "platform_max_concurrent_executions": 0,
            "spend_today": {},
            "spend_mtd": {}
          }
        ]
      },
      "AiBillingCreate": {
        "type": "object",
        "description": "The `ai_billing` fields a client may set on create.",
        "properties": {
          "monthly_limit": {
            "description": "The most the account may spend on the platform's key in a calendar month (UTC), as Money. A run that could take the month past it is refused before it starts. Leave it unset for no limit.",
            "x-field-behavior": "OPTIONAL"
          },
          "daily_limit": {
            "description": "The most the account may spend on the platform's key in a calendar day (UTC), as Money. A run that could take the day past it is refused before it starts.",
            "x-field-behavior": "OPTIONAL"
          },
          "max_concurrent_executions": {
            "type": "integer",
            "format": "int64",
            "description": "The most runs the account may have queued or running at once, on any connection. A run created past it is refused with `CONCURRENCY_LIMIT_REACHED`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              5
            ]
          }
        },
        "examples": [
          {
            "monthly_limit": {},
            "daily_limit": {}
          }
        ]
      },
      "AiBillingUpdate": {
        "type": "object",
        "description": "The `ai_billing` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "monthly_limit": {
            "description": "The most the account may spend on the platform's key in a calendar month (UTC), as Money. A run that could take the month past it is refused before it starts. Leave it unset for no limit.",
            "x-field-behavior": "OPTIONAL"
          },
          "daily_limit": {
            "description": "The most the account may spend on the platform's key in a calendar day (UTC), as Money. A run that could take the day past it is refused before it starts.",
            "x-field-behavior": "OPTIONAL"
          },
          "max_concurrent_executions": {
            "type": "integer",
            "format": "int64",
            "description": "The most runs the account may have queued or running at once, on any connection. A run created past it is refused with `CONCURRENCY_LIMIT_REACHED`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              5
            ]
          }
        },
        "examples": [
          {
            "monthly_limit": {},
            "daily_limit": {}
          }
        ]
      },
      "AiTransaction": {
        "type": "object",
        "description": "The account's AI ledger: every charge for a run on the platform's key and every change the platform made to the balance, newest first. Rows are never edited or deleted \u2014 a correction is a row of its own.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_transactions/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "type": {
            "type": "string",
            "description": "`CHARGE` for a run on the platform's key; `TOP_UP`, `REFUND`, `ADJUSTMENT` or `BONUS` for a change made by the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "CHARGE"
            ]
          },
          "amount": {
            "description": "The row's amount as Money, signed: negative for a charge, positive for money put in.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "balance_after": {
            "description": "The balance right after this row, as Money, so a statement reads without adding up the rows before it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "execution_id": {
            "type": "string",
            "description": "The `ai_executions` entry a `CHARGE` is for. Absent on every other type.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "usage_record_id": {
            "type": "string",
            "description": "The `ai_usage_records` entry \u2014 the attempt and its token counts \u2014 a `CHARGE` was priced from.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f609"
            ]
          },
          "pricing_id": {
            "type": "string",
            "description": "The price row a `CHARGE` was priced at. Price rows never change, so a later price change does not restate it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f60a"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the row is for, in words: the run and attempt of a charge, or the reason given for a change.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Run 64ff1f77aa01b2c3d4e5f607, attempt 1, on claude-haiku-4-5"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_transactions/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "type": "CHARGE",
            "amount": {},
            "balance_after": {},
            "execution_id": "64ff1f77aa01b2c3d4e5f607",
            "usage_record_id": "64ff1f77aa01b2c3d4e5f609",
            "pricing_id": "64ff1f77aa01b2c3d4e5f60a",
            "description": "Run 64ff1f77aa01b2c3d4e5f607, attempt 1, on claude-haiku-4-5"
          }
        ]
      },
      "AiTransactionCreate": {
        "type": "object",
        "description": "The `ai_transactions` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiTransactionUpdate": {
        "type": "object",
        "description": "The `ai_transactions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiUsageRecord": {
        "type": "object",
        "description": "What each attempt of the account's AI runs consumed, in tokens \u2014 for runs on the account's own provider key as much as for runs charged to the balance. One entry per attempt whose token counts the provider reported, newest first.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_usage_records/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "execution_id": {
            "type": "string",
            "description": "The `ai_executions` entry the attempt belongs to.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "attempt": {
            "type": "integer",
            "format": "int64",
            "description": "The number of the attempt within its run, as in the run's `attempts`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1
            ]
          },
          "agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry the run executed.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f608"
            ]
          },
          "model_id": {
            "type": "string",
            "description": "The `ai_models` entry the attempt ran on.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "claude-haiku-4-5"
            ]
          },
          "provider": {
            "type": "string",
            "description": "The AI provider that served the attempt, by the platform's name for it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "anthropic"
            ]
          },
          "connection_mode": {
            "type": "string",
            "description": "Whose key the attempt used: `BYOK` (the account's own, billed by the provider) or `MANAGED` (the platform's, charged to the AI balance).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "MANAGED"
            ]
          },
          "input_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "Input tokens the provider counted for the attempt, cache reads and writes not included.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1000
            ]
          },
          "output_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "Output tokens the provider counted for the attempt.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              250
            ]
          },
          "cache_read_input_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "Input tokens the provider served from its prompt cache.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              0
            ]
          },
          "cache_creation_input_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "Input tokens the provider wrote to its prompt cache.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              0
            ]
          },
          "raw_usage": {
            "description": "The provider's own usage object for the attempt, exactly as it arrived, kept beside the four counters above.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_usage_records/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "execution_id": "64ff1f77aa01b2c3d4e5f607",
            "attempt": 1,
            "agent_id": "64ff1f77aa01b2c3d4e5f608",
            "model_id": "claude-haiku-4-5",
            "provider": "anthropic",
            "connection_mode": "MANAGED",
            "input_tokens": 1000,
            "output_tokens": 250,
            "cache_read_input_tokens": 0,
            "cache_creation_input_tokens": 0,
            "raw_usage": {}
          }
        ]
      },
      "AiUsageRecordCreate": {
        "type": "object",
        "description": "The `ai_usage_records` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiUsageRecordUpdate": {
        "type": "object",
        "description": "The `ai_usage_records` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiAgent": {
        "type": "object",
        "description": "The reusable settings of an AI run in an account: which instruction it follows, which model it runs on, how hard it tries and how long it waits. Every change is a new `version`, and the settings of each version are kept, so what any run used can be looked up later.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_agents/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label that tells this agent apart in a list. Required on create unless `source_system_agent` supplies it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Blog writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the agent is for, for the people who maintain it.",
            "x-field-behavior": "OPTIONAL"
          },
          "instruction_id": {
            "type": "string",
            "description": "The id of the account's `ai_instructions` entry this agent runs. Required on create unless `source_system_agent` is set, which creates the instruction too.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "instruction_version": {
            "type": "integer",
            "format": "int64",
            "description": "Pin the agent to one version of its instruction. Absent means the instruction's `active_version` at the moment a run starts.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          },
          "preferred_model_id": {
            "type": "string",
            "description": "The `ai_models` entry a run uses when it does not name a model. Must be AVAILABLE when set, and able to run what this agent asks of it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "allowed_model_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The only models a run of this agent may name. Empty means any available model; when not empty, it must include `preferred_model_id`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              [
                "claude-opus-5",
                "claude-sonnet-5"
              ]
            ]
          },
          "max_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "The most tokens one run may write, at most the model's `max_output_tokens`. Defaults to 16000.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              16000
            ]
          },
          "effort": {
            "type": "string",
            "description": "How hard the model is asked to think: `LOW`, `MEDIUM`, `HIGH`, `XHIGH` or `MAX`. Leave it unset for the model's default \u2014 and on a model without the `EFFORT` capability, which refuses any level.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "HIGH"
            ]
          },
          "output_format": {
            "type": "string",
            "description": "`TEXT` (the default); `JSON` \u2014 an answer that follows `output_schema`, on a model with `STRUCTURED_OUTPUT`; or `IMAGE` \u2014 a picture, on a model with `IMAGE_GENERATION`, whose rendered instruction is the prompt and whose result is an artifact of the run rather than text.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "TEXT"
            ]
          },
          "output_schema": {
            "description": "The JSON Schema object a JSON agent's answer must follow. Required when `output_format` is JSON and refused otherwise.",
            "x-field-behavior": "OPTIONAL"
          },
          "image_width": {
            "type": "integer",
            "format": "int64",
            "description": "The width of the picture an IMAGE agent asks for, in pixels, 64 to 4096; defaults to 1024. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              1600
            ]
          },
          "image_height": {
            "type": "integer",
            "format": "int64",
            "description": "The height of the picture an IMAGE agent asks for, in pixels, 64 to 4096; defaults to 1024. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              900
            ]
          },
          "image_quality": {
            "type": "string",
            "description": "How much care an IMAGE agent's picture is drawn with: `LOW`, `MEDIUM`, `HIGH`, `XHIGH` or `MAX`. Interpreted by the model's provider: on `openai` it is the picture's `quality`, and a higher one produces more output tokens; `bfl` has no such setting and ignores it. Leave it unset for the provider's default. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "HIGH"
            ]
          },
          "connection_mode": {
            "type": "string",
            "description": "Which of the account's connections a run may be authorized through: `ANY` (the default), `BYOK_ONLY` or `MANAGED_ONLY`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "ANY"
            ]
          },
          "max_attempts": {
            "type": "integer",
            "format": "int64",
            "description": "How many times a run is tried when the provider fails in a way worth retrying: 1 to 10, default 3.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              3
            ]
          },
          "timeout": {
            "type": "string",
            "description": "How long one call to the provider may take: a number of seconds with the `s` suffix, 1s to 600s. Defaults to `120s`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "120s"
            ]
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tools the model may call. Must be empty: tool calling is not available yet.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              []
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether the agent may run. Switch it off to stop new runs without deleting it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              true
            ]
          },
          "version": {
            "type": "integer",
            "format": "int64",
            "description": "The configuration's version: 1 on create, and one more on every update. Each version's settings are kept under `versions`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              4
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_agents/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Blog writer",
            "description": "string",
            "instruction_id": "64ff1f77aa01b2c3d4e5f607",
            "instruction_version": 2,
            "preferred_model_id": "claude-opus-5",
            "allowed_model_ids": [
              "claude-opus-5",
              "claude-sonnet-5"
            ],
            "max_tokens": 16000,
            "effort": "HIGH",
            "output_format": "TEXT",
            "output_schema": {},
            "image_width": 1600,
            "image_height": 900,
            "image_quality": "HIGH",
            "connection_mode": "ANY",
            "max_attempts": 3,
            "timeout": "120s",
            "allowed_tools": [],
            "is_enabled": true,
            "version": 4
          }
        ]
      },
      "AiAgentCreate": {
        "type": "object",
        "description": "The `ai_agents` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The label that tells this agent apart in a list. Required on create unless `source_system_agent` supplies it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Blog writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the agent is for, for the people who maintain it.",
            "x-field-behavior": "OPTIONAL"
          },
          "instruction_id": {
            "type": "string",
            "description": "The id of the account's `ai_instructions` entry this agent runs. Required on create unless `source_system_agent` is set, which creates the instruction too.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "instruction_version": {
            "type": "integer",
            "format": "int64",
            "description": "Pin the agent to one version of its instruction. Absent means the instruction's `active_version` at the moment a run starts.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          },
          "preferred_model_id": {
            "type": "string",
            "description": "The `ai_models` entry a run uses when it does not name a model. Must be AVAILABLE when set, and able to run what this agent asks of it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "allowed_model_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The only models a run of this agent may name. Empty means any available model; when not empty, it must include `preferred_model_id`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              [
                "claude-opus-5",
                "claude-sonnet-5"
              ]
            ]
          },
          "max_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "The most tokens one run may write, at most the model's `max_output_tokens`. Defaults to 16000.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              16000
            ]
          },
          "effort": {
            "type": "string",
            "description": "How hard the model is asked to think: `LOW`, `MEDIUM`, `HIGH`, `XHIGH` or `MAX`. Leave it unset for the model's default \u2014 and on a model without the `EFFORT` capability, which refuses any level.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "HIGH"
            ]
          },
          "output_format": {
            "type": "string",
            "description": "`TEXT` (the default); `JSON` \u2014 an answer that follows `output_schema`, on a model with `STRUCTURED_OUTPUT`; or `IMAGE` \u2014 a picture, on a model with `IMAGE_GENERATION`, whose rendered instruction is the prompt and whose result is an artifact of the run rather than text.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "TEXT"
            ]
          },
          "output_schema": {
            "description": "The JSON Schema object a JSON agent's answer must follow. Required when `output_format` is JSON and refused otherwise.",
            "x-field-behavior": "OPTIONAL"
          },
          "image_width": {
            "type": "integer",
            "format": "int64",
            "description": "The width of the picture an IMAGE agent asks for, in pixels, 64 to 4096; defaults to 1024. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              1600
            ]
          },
          "image_height": {
            "type": "integer",
            "format": "int64",
            "description": "The height of the picture an IMAGE agent asks for, in pixels, 64 to 4096; defaults to 1024. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              900
            ]
          },
          "image_quality": {
            "type": "string",
            "description": "How much care an IMAGE agent's picture is drawn with: `LOW`, `MEDIUM`, `HIGH`, `XHIGH` or `MAX`. Interpreted by the model's provider: on `openai` it is the picture's `quality`, and a higher one produces more output tokens; `bfl` has no such setting and ignores it. Leave it unset for the provider's default. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "HIGH"
            ]
          },
          "connection_mode": {
            "type": "string",
            "description": "Which of the account's connections a run may be authorized through: `ANY` (the default), `BYOK_ONLY` or `MANAGED_ONLY`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "ANY"
            ]
          },
          "max_attempts": {
            "type": "integer",
            "format": "int64",
            "description": "How many times a run is tried when the provider fails in a way worth retrying: 1 to 10, default 3.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              3
            ]
          },
          "timeout": {
            "type": "string",
            "description": "How long one call to the provider may take: a number of seconds with the `s` suffix, 1s to 600s. Defaults to `120s`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "120s"
            ]
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tools the model may call. Must be empty: tool calling is not available yet.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              []
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether the agent may run. Switch it off to stop new runs without deleting it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              true
            ]
          },
          "source_system_agent": {
            "type": "string",
            "description": "Create only: the id of an `ai_system_agents` entry to copy. Its settings and its instruction text \u2014 as a new instruction of this account \u2014 become the new agent's, under any fields the body also sets.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "mooverapp-writer"
            ]
          }
        },
        "examples": [
          {
            "display_name": "Blog writer",
            "description": "string"
          }
        ]
      },
      "AiAgentUpdate": {
        "type": "object",
        "description": "The `ai_agents` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The label that tells this agent apart in a list. Required on create unless `source_system_agent` supplies it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Blog writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the agent is for, for the people who maintain it.",
            "x-field-behavior": "OPTIONAL"
          },
          "instruction_id": {
            "type": "string",
            "description": "The id of the account's `ai_instructions` entry this agent runs. Required on create unless `source_system_agent` is set, which creates the instruction too.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "instruction_version": {
            "type": "integer",
            "format": "int64",
            "description": "Pin the agent to one version of its instruction. Absent means the instruction's `active_version` at the moment a run starts.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          },
          "preferred_model_id": {
            "type": "string",
            "description": "The `ai_models` entry a run uses when it does not name a model. Must be AVAILABLE when set, and able to run what this agent asks of it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "allowed_model_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The only models a run of this agent may name. Empty means any available model; when not empty, it must include `preferred_model_id`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              [
                "claude-opus-5",
                "claude-sonnet-5"
              ]
            ]
          },
          "max_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "The most tokens one run may write, at most the model's `max_output_tokens`. Defaults to 16000.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              16000
            ]
          },
          "effort": {
            "type": "string",
            "description": "How hard the model is asked to think: `LOW`, `MEDIUM`, `HIGH`, `XHIGH` or `MAX`. Leave it unset for the model's default \u2014 and on a model without the `EFFORT` capability, which refuses any level.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "HIGH"
            ]
          },
          "output_format": {
            "type": "string",
            "description": "`TEXT` (the default); `JSON` \u2014 an answer that follows `output_schema`, on a model with `STRUCTURED_OUTPUT`; or `IMAGE` \u2014 a picture, on a model with `IMAGE_GENERATION`, whose rendered instruction is the prompt and whose result is an artifact of the run rather than text.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "TEXT"
            ]
          },
          "output_schema": {
            "description": "The JSON Schema object a JSON agent's answer must follow. Required when `output_format` is JSON and refused otherwise.",
            "x-field-behavior": "OPTIONAL"
          },
          "image_width": {
            "type": "integer",
            "format": "int64",
            "description": "The width of the picture an IMAGE agent asks for, in pixels, 64 to 4096; defaults to 1024. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              1600
            ]
          },
          "image_height": {
            "type": "integer",
            "format": "int64",
            "description": "The height of the picture an IMAGE agent asks for, in pixels, 64 to 4096; defaults to 1024. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              900
            ]
          },
          "image_quality": {
            "type": "string",
            "description": "How much care an IMAGE agent's picture is drawn with: `LOW`, `MEDIUM`, `HIGH`, `XHIGH` or `MAX`. Interpreted by the model's provider: on `openai` it is the picture's `quality`, and a higher one produces more output tokens; `bfl` has no such setting and ignores it. Leave it unset for the provider's default. Refused on a TEXT or JSON agent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "HIGH"
            ]
          },
          "connection_mode": {
            "type": "string",
            "description": "Which of the account's connections a run may be authorized through: `ANY` (the default), `BYOK_ONLY` or `MANAGED_ONLY`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "ANY"
            ]
          },
          "max_attempts": {
            "type": "integer",
            "format": "int64",
            "description": "How many times a run is tried when the provider fails in a way worth retrying: 1 to 10, default 3.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              3
            ]
          },
          "timeout": {
            "type": "string",
            "description": "How long one call to the provider may take: a number of seconds with the `s` suffix, 1s to 600s. Defaults to `120s`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "120s"
            ]
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tools the model may call. Must be empty: tool calling is not available yet.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              []
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether the agent may run. Switch it off to stop new runs without deleting it.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              true
            ]
          },
          "source_system_agent": {
            "type": "string",
            "description": "Create only: the id of an `ai_system_agents` entry to copy. Its settings and its instruction text \u2014 as a new instruction of this account \u2014 become the new agent's, under any fields the body also sets.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "mooverapp-writer"
            ]
          }
        },
        "examples": [
          {
            "display_name": "Blog writer",
            "description": "string"
          }
        ]
      },
      "AiAgentVersion": {
        "type": "object",
        "description": "The immutable settings of an agent at one version, written by the update that produced it. `create_time` is when that version took effect, so the settings in force at any moment are those of the latest version created before it.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_agents/9c2d40f7e1ab/versions/4"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "4"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "ai_agent_id": {
            "type": "string",
            "description": "The agent this is a version of. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "version": {
            "type": "integer",
            "format": "int64",
            "description": "The version number \u2014 also this resource's `id`, and the `version` the agent had.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true,
            "examples": [
              4
            ]
          },
          "snapshot": {
            "description": "The agent exactly as it stood at this version: every field of the agent resource, except `etag`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "created_by": {
            "type": "string",
            "description": "The user whose write produced this version, as `users/{user}`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "users/64ff1f77aa01b2c3d4e5f607"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_agents/9c2d40f7e1ab/versions/4",
            "id": "4",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "ai_agent_id": "string",
            "version": 4,
            "snapshot": {},
            "created_by": "users/64ff1f77aa01b2c3d4e5f607"
          }
        ]
      },
      "AiAgentVersionCreate": {
        "type": "object",
        "description": "The `versions` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiAgentVersionUpdate": {
        "type": "object",
        "description": "The `versions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiConnection": {
        "type": "object",
        "description": "How an account's AI runs are authorized with a provider: its own API key (`BYOK`), or permission to use the platform's key and pay from the AI balance (`MANAGED`). Every account has one `MANAGED` connection per provider from the moment it exists; add `BYOK` connections for keys of your own.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_connections/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "provider": {
            "type": "string",
            "description": "The AI provider this connection reaches, by the platform's name for it. Set on create and fixed afterwards: a stored key belongs to exactly one provider.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "anthropic"
            ]
          },
          "mode": {
            "type": "string",
            "description": "`BYOK` \u2014 your own provider API key, used without touching your AI balance \u2014 or `MANAGED`, the platform's key, charged to the balance. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "BYOK"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label that tells this connection apart in a list, such as `Production key`. Free text.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Production key"
            ]
          },
          "key_hint": {
            "type": "string",
            "description": "The last four characters of the stored key \u2014 the only part of it any response carries, so that two keys can be told apart. Absent on a `MANAGED` connection, which has no key of its own.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Qk9f"
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether runs may use this connection. Switch it off to stop a key being used without deleting it \u2014 and to turn managed access off for the account, since a `MANAGED` connection cannot be deleted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              true
            ]
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "The order connections are tried in when an agent may use more than one: lower goes first. Your keys start at 0 and the managed connection at 100, so a key you add is used before your balance is.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              0
            ]
          },
          "status": {
            "type": "string",
            "description": "What the platform last learned about the key: `UNVERIFIED` until it is checked, then `VALID` or `INVALID` \u2014 moved by `:verify`, and by a run the provider refused for the key's sake. `EXPIRED` is reserved for providers that report it. Always `UNVERIFIED` on a `MANAGED` connection, which has no key of its own to learn anything about.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "VALID"
            ]
          },
          "last_verify_time": {
            "type": "string",
            "format": "date-time",
            "description": "When `status` was last decided by asking the provider (RFC 3339, UTC); cleared when the key is replaced, and absent on a `MANAGED` connection. Sort by it together with a `provider` filter \u2014 that is the pair an index backs.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_connections/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "provider": "anthropic",
            "mode": "BYOK",
            "display_name": "Production key",
            "key_hint": "Qk9f",
            "is_enabled": true,
            "priority": 0,
            "status": "VALID",
            "last_verify_time": "2026-01-15T09:30:00Z"
          }
        ]
      },
      "AiConnectionCreate": {
        "type": "object",
        "description": "The `ai_connections` fields a client may set on create.",
        "properties": {
          "provider": {
            "type": "string",
            "description": "The AI provider this connection reaches, by the platform's name for it. Set on create and fixed afterwards: a stored key belongs to exactly one provider.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "anthropic"
            ]
          },
          "mode": {
            "type": "string",
            "description": "`BYOK` \u2014 your own provider API key, used without touching your AI balance \u2014 or `MANAGED`, the platform's key, charged to the balance. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "BYOK"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label that tells this connection apart in a list, such as `Production key`. Free text.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Production key"
            ]
          },
          "api_key": {
            "type": "string",
            "description": "The provider API key. Required when creating a `BYOK` connection and refused on `MANAGED`; send it on Update to replace the stored key. It is encrypted before it is stored and no call ever returns it \u2014 `key_hint` is all that comes back.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "your-provider-api-key"
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether runs may use this connection. Switch it off to stop a key being used without deleting it \u2014 and to turn managed access off for the account, since a `MANAGED` connection cannot be deleted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              true
            ]
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "The order connections are tried in when an agent may use more than one: lower goes first. Your keys start at 0 and the managed connection at 100, so a key you add is used before your balance is.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              0
            ]
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Production key"
          }
        ]
      },
      "AiConnectionUpdate": {
        "type": "object",
        "description": "The `ai_connections` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The label that tells this connection apart in a list, such as `Production key`. Free text.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Production key"
            ]
          },
          "api_key": {
            "type": "string",
            "description": "The provider API key. Required when creating a `BYOK` connection and refused on `MANAGED`; send it on Update to replace the stored key. It is encrypted before it is stored and no call ever returns it \u2014 `key_hint` is all that comes back.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "your-provider-api-key"
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether runs may use this connection. Switch it off to stop a key being used without deleting it \u2014 and to turn managed access off for the account, since a `MANAGED` connection cannot be deleted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              true
            ]
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "The order connections are tried in when an agent may use more than one: lower goes first. Your keys start at 0 and the managed connection at 100, so a key you add is used before your balance is.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              0
            ]
          }
        },
        "examples": [
          {
            "display_name": "Production key"
          }
        ]
      },
      "AiExecution": {
        "type": "object",
        "description": "One run of an agent in an account: what was asked, which model and connection ran it, what came back, what it consumed, and every attempt in between. Runs are carried out in the background \u2014 create one, then read it until `state` is final.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_executions/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "agent_id": {
            "type": "string",
            "description": "The id of the account's `ai_agents` entry this run executes. Set on create and fixed afterwards.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "agent_version": {
            "type": "integer",
            "format": "int64",
            "description": "The version of the agent this run uses, resolved when the run was created. Its settings are kept under the agent's `versions`, so the run can be reproduced after the agent changes.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              4
            ]
          },
          "instruction_version": {
            "type": "integer",
            "format": "int64",
            "description": "The version of the agent's instruction whose text this run uses, resolved when the run was created.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              2
            ]
          },
          "model_id": {
            "type": "string",
            "description": "The `ai_models` entry the run uses. Leave it out to use the agent's `preferred_model_id`; when the agent lists `allowed_model_ids`, only those can be named.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "provider": {
            "type": "string",
            "description": "The AI provider of the run's model, by the platform's name for it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "anthropic"
            ]
          },
          "input": {
            "description": "What the run works on: `variables`, an object filling every `{{variable}}` the instruction uses (strings, integers or booleans), and optionally `text` \u2014 material for the instruction to act on, such as a page to translate.",
            "x-field-behavior": "REQUIRED"
          },
          "state": {
            "type": "string",
            "description": "`QUEUED`, `RUNNING`, then `SUCCEEDED`, `FAILED`, `CANCELLED` or `EXPIRED`. A retryable failure puts the run back to `QUEUED` until its attempts run out.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "SUCCEEDED"
            ]
          },
          "connection_id": {
            "type": "string",
            "description": "The `ai_connections` entry the latest attempt was authorized through. Absent until an attempt was routed.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f608"
            ]
          },
          "connection_mode": {
            "type": "string",
            "description": "Whose key the latest attempt used: `BYOK` (the account's own) or `MANAGED` (the platform's, paid from the AI balance).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "BYOK"
            ]
          },
          "usage": {
            "description": "What the run consumed, summed over every attempt that reported it: `input_tokens`, `output_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`, and for an IMAGE run `image_count` and `megapixels_milli` (thousandths of a megapixel).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "cost": {
            "description": "What the run was charged to the AI balance, summed over its attempts, as Money. Present once an attempt on the platform's key (`MANAGED`) was charged; a run on the account's own key has no cost here, because the provider bills the account directly.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "output": {
            "description": "The result of a `SUCCEEDED` run: `text`, or `json` for an agent with `output_format` JSON, or `artifacts` for an IMAGE agent \u2014 each with its `storage_key`, `mime_type`, `width`, `height` and `byte_size`, the bytes living in the platform's store \u2014 and `output_truncated`, true when a text answer stopped at `max_tokens`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "error": {
            "description": "Why a `FAILED` or `EXPIRED` run stopped, in the same shape as an API error: `code`, `status`, `message` and, where there is one, a `PRECONDITION_FAILURE` whose `type` says why.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "attempts": {
            "description": "Every attempt, in order: `number`, `start_time`, `end_time`, `http_status` (0 when no response arrived), `error_code`, `message`, and `usage` when the attempt's usage is known.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "source_module": {
            "type": "string",
            "description": "Who started the run, in the caller's own words \u2014 `editorial`, `import`. Stored and filterable, never interpreted. Fixed after create.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "editorial"
            ]
          },
          "source_id": {
            "type": "string",
            "description": "The caller's own reference for what the run is for, within `source_module`, which it requires. Filter by it together with `source_module`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "slot-2026-09-14"
            ]
          },
          "metadata": {
            "description": "Any other correlation the caller wants back with the run, as an object of at most 16 KB. Returned as sent; not filterable.",
            "x-field-behavior": "OPTIONAL"
          },
          "expire_time": {
            "type": "string",
            "format": "date-time",
            "description": "A deadline for starting: a run not started by then becomes `EXPIRED` without calling the provider (RFC 3339, UTC). Sort by it together with a `state` filter.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          },
          "start_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the first attempt started (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          },
          "end_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the run reached the state it is in, if that state is final (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_executions/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "agent_id": "64ff1f77aa01b2c3d4e5f607",
            "agent_version": 4,
            "instruction_version": 2,
            "model_id": "claude-opus-5",
            "provider": "anthropic",
            "input": {},
            "state": "SUCCEEDED",
            "connection_id": "64ff1f77aa01b2c3d4e5f608",
            "connection_mode": "BYOK",
            "usage": {},
            "cost": {},
            "output": {},
            "error": {},
            "attempts": {},
            "source_module": "editorial",
            "source_id": "slot-2026-09-14",
            "metadata": {},
            "expire_time": "2026-01-15T09:30:00Z",
            "start_time": "2026-01-15T09:30:00Z",
            "end_time": "2026-01-15T09:30:00Z"
          }
        ]
      },
      "AiExecutionCreate": {
        "type": "object",
        "description": "The `ai_executions` fields a client may set on create.",
        "properties": {
          "agent_id": {
            "type": "string",
            "description": "The id of the account's `ai_agents` entry this run executes. Set on create and fixed afterwards.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "model_id": {
            "type": "string",
            "description": "The `ai_models` entry the run uses. Leave it out to use the agent's `preferred_model_id`; when the agent lists `allowed_model_ids`, only those can be named.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "input": {
            "description": "What the run works on: `variables`, an object filling every `{{variable}}` the instruction uses (strings, integers or booleans), and optionally `text` \u2014 material for the instruction to act on, such as a page to translate.",
            "x-field-behavior": "REQUIRED"
          },
          "source_module": {
            "type": "string",
            "description": "Who started the run, in the caller's own words \u2014 `editorial`, `import`. Stored and filterable, never interpreted. Fixed after create.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "editorial"
            ]
          },
          "source_id": {
            "type": "string",
            "description": "The caller's own reference for what the run is for, within `source_module`, which it requires. Filter by it together with `source_module`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "slot-2026-09-14"
            ]
          },
          "metadata": {
            "description": "Any other correlation the caller wants back with the run, as an object of at most 16 KB. Returned as sent; not filterable.",
            "x-field-behavior": "OPTIONAL"
          },
          "expire_time": {
            "type": "string",
            "format": "date-time",
            "description": "A deadline for starting: a run not started by then becomes `EXPIRED` without calling the provider (RFC 3339, UTC). Sort by it together with a `state` filter.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          },
          "request_id": {
            "type": "string",
            "description": "An idempotency key you choose, at most 64 characters. Creating with a key already used returns the run that key created instead of starting another.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "3f6c1b8e-6b7a-4f0e-9d53-2d8a0c1e7b42"
            ]
          }
        },
        "required": [
          "agent_id",
          "input"
        ],
        "examples": [
          {
            "agent_id": "64ff1f77aa01b2c3d4e5f607",
            "input": {}
          }
        ]
      },
      "AiExecutionUpdate": {
        "type": "object",
        "description": "The `ai_executions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "agent_id": {
            "type": "string",
            "description": "The id of the account's `ai_agents` entry this run executes. Set on create and fixed afterwards.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "model_id": {
            "type": "string",
            "description": "The `ai_models` entry the run uses. Leave it out to use the agent's `preferred_model_id`; when the agent lists `allowed_model_ids`, only those can be named.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "input": {
            "description": "What the run works on: `variables`, an object filling every `{{variable}}` the instruction uses (strings, integers or booleans), and optionally `text` \u2014 material for the instruction to act on, such as a page to translate.",
            "x-field-behavior": "REQUIRED"
          },
          "source_module": {
            "type": "string",
            "description": "Who started the run, in the caller's own words \u2014 `editorial`, `import`. Stored and filterable, never interpreted. Fixed after create.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "editorial"
            ]
          },
          "source_id": {
            "type": "string",
            "description": "The caller's own reference for what the run is for, within `source_module`, which it requires. Filter by it together with `source_module`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "slot-2026-09-14"
            ]
          },
          "metadata": {
            "description": "Any other correlation the caller wants back with the run, as an object of at most 16 KB. Returned as sent; not filterable.",
            "x-field-behavior": "OPTIONAL"
          },
          "expire_time": {
            "type": "string",
            "format": "date-time",
            "description": "A deadline for starting: a run not started by then becomes `EXPIRED` without calling the provider (RFC 3339, UTC). Sort by it together with a `state` filter.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          },
          "request_id": {
            "type": "string",
            "description": "An idempotency key you choose, at most 64 characters. Creating with a key already used returns the run that key created instead of starting another.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "3f6c1b8e-6b7a-4f0e-9d53-2d8a0c1e7b42"
            ]
          }
        },
        "examples": [
          {
            "agent_id": "64ff1f77aa01b2c3d4e5f607",
            "input": {}
          }
        ]
      },
      "AiInstruction": {
        "type": "object",
        "description": "A prompt template of an account, kept apart from the agents that use it so that its text has a history. The text itself lives in `versions`: writing a version is the only way to change it, and `active_version` says which one runs.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_instructions/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label that tells this instruction apart in a list. Free text.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Blog article"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the instruction is for, for the people who maintain it.",
            "x-field-behavior": "OPTIONAL"
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The variable names the text may reference as `{{name}}`: lower-case letters, digits and `_`. A version that references a name not listed here is refused, and so is a run that supplies one \u2014 or leaves a referenced one out.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "topic",
                "tone"
              ]
            ]
          },
          "active_version": {
            "type": "integer",
            "format": "int64",
            "description": "The version a run uses unless its agent pins another. The first version becomes active by itself; after that, set this field to switch. Absent until a version exists.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_instructions/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Blog article",
            "description": "string",
            "variables": [
              "topic",
              "tone"
            ],
            "active_version": 2
          }
        ]
      },
      "AiInstructionCreate": {
        "type": "object",
        "description": "The `ai_instructions` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The label that tells this instruction apart in a list. Free text.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Blog article"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the instruction is for, for the people who maintain it.",
            "x-field-behavior": "OPTIONAL"
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The variable names the text may reference as `{{name}}`: lower-case letters, digits and `_`. A version that references a name not listed here is refused, and so is a run that supplies one \u2014 or leaves a referenced one out.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "topic",
                "tone"
              ]
            ]
          },
          "active_version": {
            "type": "integer",
            "format": "int64",
            "description": "The version a run uses unless its agent pins another. The first version becomes active by itself; after that, set this field to switch. Absent until a version exists.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Blog article"
          }
        ]
      },
      "AiInstructionUpdate": {
        "type": "object",
        "description": "The `ai_instructions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The label that tells this instruction apart in a list. Free text.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Blog article"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the instruction is for, for the people who maintain it.",
            "x-field-behavior": "OPTIONAL"
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The variable names the text may reference as `{{name}}`: lower-case letters, digits and `_`. A version that references a name not listed here is refused, and so is a run that supplies one \u2014 or leaves a referenced one out.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "topic",
                "tone"
              ]
            ]
          },
          "active_version": {
            "type": "integer",
            "format": "int64",
            "description": "The version a run uses unless its agent pins another. The first version becomes active by itself; after that, set this field to switch. Absent until a version exists.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          }
        },
        "examples": [
          {
            "display_name": "Blog article"
          }
        ]
      },
      "AiInstructionVersion": {
        "type": "object",
        "description": "An immutable text of an instruction. Versions are numbered from 1 and never edited or deleted: to change the text, create the next version, then point the instruction's `active_version` at it if it is not the first.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/ai_instructions/9c2d40f7e1ab/versions/2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "ai_instruction_id": {
            "type": "string",
            "description": "The instruction this is a version of. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "version": {
            "type": "integer",
            "format": "int64",
            "description": "The version number \u2014 also this resource's `id`. Assigned by the server: one more than the instruction's latest.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true,
            "examples": [
              2
            ]
          },
          "content": {
            "type": "string",
            "description": "The template text. `{{name}}` is replaced by the run's value for `name`, which must be one of the instruction's `variables`; any other text, other braces included, is sent as written.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Write a short article about {{topic}} in a {{tone}} voice."
            ]
          },
          "notes": {
            "type": "string",
            "description": "Why this version exists \u2014 the one thing a comparison of two texts cannot tell you.",
            "x-field-behavior": "OPTIONAL"
          },
          "created_by": {
            "type": "string",
            "description": "The user who wrote this version, as `users/{user}`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "users/64ff1f77aa01b2c3d4e5f607"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/ai_instructions/9c2d40f7e1ab/versions/2",
            "id": "2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "ai_instruction_id": "string",
            "version": 2,
            "content": "Write a short article about {{topic}} in a {{tone}} voice.",
            "notes": "string",
            "created_by": "users/64ff1f77aa01b2c3d4e5f607"
          }
        ]
      },
      "AiInstructionVersionCreate": {
        "type": "object",
        "description": "The `versions` fields a client may set on create.",
        "properties": {
          "content": {
            "type": "string",
            "description": "The template text. `{{name}}` is replaced by the run's value for `name`, which must be one of the instruction's `variables`; any other text, other braces included, is sent as written.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Write a short article about {{topic}} in a {{tone}} voice."
            ]
          },
          "notes": {
            "type": "string",
            "description": "Why this version exists \u2014 the one thing a comparison of two texts cannot tell you.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "content"
        ],
        "examples": [
          {
            "content": "Write a short article about {{topic}} in a {{tone}} voice."
          }
        ]
      },
      "AiInstructionVersionUpdate": {
        "type": "object",
        "description": "The `versions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "content": {
            "type": "string",
            "description": "The template text. `{{name}}` is replaced by the run's value for `name`, which must be one of the instruction's `variables`; any other text, other braces included, is sent as written.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Write a short article about {{topic}} in a {{tone}} voice."
            ]
          },
          "notes": {
            "type": "string",
            "description": "Why this version exists \u2014 the one thing a comparison of two texts cannot tell you.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "content": "Write a short article about {{topic}} in a {{tone}} voice."
          }
        ]
      },
      "AiModel": {
        "type": "object",
        "description": "The models an AI agent can run on, with what each one can do. The catalogue belongs to the platform: read it to choose an agent's `preferred_model_id`. Prices are not part of a model \u2014 `platform_priced` says only whether there is one; what a run costs is recorded on the run.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "ai_models/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "provider": {
            "type": "string",
            "description": "The provider that serves this model, by the platform's name for it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "anthropic"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "The provider's own identifier for the model \u2014 what a run sends it. It can move to a newer snapshot of the model while `id`, the name agents store, stays the same.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "claude-opus-5"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The model's name as a person reads it, for a picker.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Claude Opus 5"
            ]
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the model can do. `TEXT_GENERATION` to run a text agent at all; `STRUCTURED_OUTPUT` to run an agent whose `output_format` is JSON; `EFFORT` to accept an agent's `effort`; `IMAGE_GENERATION` to run an IMAGE agent; `VISION` and `TOOL_CALLING` are listed for later use.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              [
                "TEXT_GENERATION",
                "STRUCTURED_OUTPUT",
                "EFFORT"
              ]
            ]
          },
          "max_input_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "The largest prompt the model accepts, in tokens.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1000000
            ]
          },
          "max_output_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "The largest `max_tokens` an agent may set and still run on this model.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              128000
            ]
          },
          "state": {
            "type": "string",
            "description": "`AVAILABLE` models run. `DEPRECATED` and `DISABLED` ones do not, and an agent cannot be pointed at one \u2014 the platform takes a model out of service with this field, without a release.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "AVAILABLE"
            ]
          },
          "tier": {
            "type": "string",
            "description": "A rough place on the speed-to-capability scale: `FAST`, `BALANCED` or `POWERFUL`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "POWERFUL"
            ]
          },
          "platform_priced": {
            "type": "boolean",
            "description": "Whether the platform has a price for what this model does \u2014 for an `IMAGE_GENERATION` model, a price for pictures in the unit its provider bills them by (per picture, or by tokens) \u2014 so a run on the platform's key can be charged. When it is `false`, a run on the platform's key is refused with `MODEL_NOT_PRICED`, and the model runs only on the account's own connection to its provider.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              true
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "ai_models/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "provider": "anthropic",
            "external_id": "claude-opus-5",
            "display_name": "Claude Opus 5",
            "capabilities": [
              "TEXT_GENERATION",
              "STRUCTURED_OUTPUT",
              "EFFORT"
            ],
            "max_input_tokens": 1000000,
            "max_output_tokens": 128000,
            "state": "AVAILABLE",
            "tier": "POWERFUL",
            "platform_priced": true
          }
        ]
      },
      "AiModelCreate": {
        "type": "object",
        "description": "The `ai_models` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiModelUpdate": {
        "type": "object",
        "description": "The `ai_models` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiSystemAgent": {
        "type": "object",
        "description": "The agents the platform ships, ready to copy into an account. Read one to see its instruction and settings; create an agent with `source_system_agent` set to its id to get a copy of your own. A copy does not follow later changes to the original.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "ai_system_agents/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The agent's name as a person reads it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "MooverApp Writer"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the agent is for, in a sentence or two.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "instruction_text": {
            "type": "string",
            "description": "The agent's prompt template, with `{{variable}}` references. A copy of the agent starts from this text as version 1 of its own instruction.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "instruction_version": {
            "type": "integer",
            "format": "int64",
            "description": "Which revision of `instruction_text` this is; it rises whenever the platform changes the text.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1
            ]
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The variable names `instruction_text` references \u2014 the values a run of this agent is given.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                "topic",
                "brief",
                "tone"
              ]
            ]
          },
          "preferred_model_id": {
            "type": "string",
            "description": "The model a run uses when it does not name one.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "claude-opus-5"
            ]
          },
          "allowed_model_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The only models a run may name; empty means any available model.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              []
            ]
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tools the model may call. Always empty: tool calling is not available yet.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              []
            ]
          },
          "max_tokens": {
            "type": "integer",
            "format": "int64",
            "description": "The most tokens one run may write.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              16000
            ]
          },
          "effort": {
            "type": "string",
            "description": "How hard the model is asked to think: `LOW` to `MAX`. Absent means the model's own default.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "HIGH"
            ]
          },
          "output_format": {
            "type": "string",
            "description": "`TEXT`, `JSON` constrained by `output_schema`, or `IMAGE` \u2014 a picture of `image_width` by `image_height`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "TEXT"
            ]
          },
          "output_schema": {
            "description": "The JSON Schema a JSON agent's answer follows. Present only when `output_format` is JSON.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "image_width": {
            "type": "integer",
            "format": "int64",
            "description": "The width of the picture an IMAGE template asks for, in pixels. Present only on an IMAGE template.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1600
            ]
          },
          "image_height": {
            "type": "integer",
            "format": "int64",
            "description": "The height of the picture an IMAGE template asks for, in pixels. Present only on an IMAGE template.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              900
            ]
          },
          "connection_mode": {
            "type": "string",
            "description": "Which connections a run may be paid through: `ANY`, `BYOK_ONLY` or `MANAGED_ONLY`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "ANY"
            ]
          },
          "max_attempts": {
            "type": "integer",
            "format": "int64",
            "description": "How many times a run is tried when the provider fails in a way worth retrying.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              3
            ]
          },
          "timeout": {
            "type": "string",
            "description": "How long one call to the provider may take, as a duration in seconds.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "120s"
            ]
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Whether the platform offers this agent. One that is switched off cannot be copied.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              true
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "ai_system_agents/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "MooverApp Writer",
            "description": "string",
            "instruction_text": "string",
            "instruction_version": 1,
            "variables": [
              "topic",
              "brief",
              "tone"
            ],
            "preferred_model_id": "claude-opus-5",
            "allowed_model_ids": [],
            "allowed_tools": [],
            "max_tokens": 16000,
            "effort": "HIGH",
            "output_format": "TEXT",
            "output_schema": {},
            "image_width": 1600,
            "image_height": 900,
            "connection_mode": "ANY",
            "max_attempts": 3,
            "timeout": "120s",
            "is_enabled": true
          }
        ]
      },
      "AiSystemAgentCreate": {
        "type": "object",
        "description": "The `ai_system_agents` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AiSystemAgentUpdate": {
        "type": "object",
        "description": "The `ai_system_agents` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AnalyticsMetric": {
        "type": "object",
        "description": "What this website's analytics can count, one row per metric, with what each number means and which periods and intervals it accepts. Nothing here is stored or writable: it is the platform's catalogue, and a metric your client does not recognise is one it should skip rather than fail on. The numbers themselves come from `:query` on one of these rows.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/analytics_metrics/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The metric's name as a person reads it, for a widget's title or a picker.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Unique visitors"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the number means and \u2014 just as importantly \u2014 what it leaves out, in a sentence or two a widget can show as help text.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "unit": {
            "type": "string",
            "description": "What the number is measured in. `COUNT` is the only unit today; it is an enum because response times and rates are the next metrics and they are not counts.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "COUNT"
            ]
          },
          "kind": {
            "type": "string",
            "description": "`EXACT` for a counter, `ESTIMATED` for a number computed from a sketch. Everything `ESTIMATED` answers `approximate: true` on `:query`, and is accurate to about 1.6 %.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "ESTIMATED"
            ]
          },
          "supported_intervals": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The steps `:query` can return a series in: `MINUTE`, `HOUR`, `DAY`. Empty means the metric is a single number and its answer carries no `points` at all.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                "MINUTE",
                "HOUR",
                "DAY"
              ]
            ]
          },
          "supported_periods": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The windows `:query` accepts: `TODAY`, `LAST_7_DAYS`, `LAST_30_DAYS`, `CUSTOM`. Empty means the metric measures its own window ending now and takes no period.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                "TODAY",
                "LAST_7_DAYS",
                "LAST_30_DAYS",
                "CUSTOM"
              ]
            ]
          },
          "default_interval": {
            "type": "string",
            "description": "The step `:query` returns when the caller names no `interval` \u2014 except for `TODAY`, which steps by `HOUR` so that today is a shape rather than one bar. Absent on a metric with no series.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "DAY"
            ]
          },
          "rolling_window": {
            "type": "string",
            "description": "For a live metric, the window it always measures, as a duration in seconds (`300s`). Absent on every metric that takes a period instead.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "300s"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/analytics_metrics/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Unique visitors",
            "description": "string",
            "unit": "COUNT",
            "kind": "ESTIMATED",
            "supported_intervals": [
              "MINUTE",
              "HOUR",
              "DAY"
            ],
            "supported_periods": [
              "TODAY",
              "LAST_7_DAYS",
              "LAST_30_DAYS",
              "CUSTOM"
            ],
            "default_interval": "DAY",
            "rolling_window": "300s"
          }
        ]
      },
      "AnalyticsMetricCreate": {
        "type": "object",
        "description": "The `analytics_metrics` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "AnalyticsMetricUpdate": {
        "type": "object",
        "description": "The `analytics_metrics` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "BlogAuthor": {
        "type": "object",
        "description": "Someone a post can be credited to: a name, a slug, a portrait and a short biography. The name, the biography and the slug are translatable per view; the portrait and `is_active` are not.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_authors/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the author is shown on the site. It is one of the two fields a view cannot override, so an author is hidden everywhere or nowhere.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "bio": {
            "type": "string",
            "description": "The short biography rendered under the byline and on the author's own page.",
            "x-field-behavior": "OPTIONAL"
          },
          "avatar_media_id": {
            "type": "string",
            "description": "The `media` resource used as the author's portrait.",
            "x-field-behavior": "OPTIONAL"
          },
          "audience": {
            "type": "string",
            "description": "Who the author's own page is for, with the values of a post's `audience`. It hides the author's page, their place in the author list and their byline from other readers; the posts they wrote stay as visible as they are, shown without the byline.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_authors/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "string",
            "slug": "string",
            "is_active": true,
            "bio": "string",
            "avatar_media_id": "string",
            "audience": "GROUPS",
            "customer_group_ids": [
              "6a5e4957db9aab43d50bfd35"
            ]
          }
        ]
      },
      "BlogAuthorCreate": {
        "type": "object",
        "description": "The `blog_authors` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the author is shown on the site. It is one of the two fields a view cannot override, so an author is hidden everywhere or nowhere.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "bio": {
            "type": "string",
            "description": "The short biography rendered under the byline and on the author's own page.",
            "x-field-behavior": "OPTIONAL"
          },
          "avatar_media_id": {
            "type": "string",
            "description": "The `media` resource used as the author's portrait.",
            "x-field-behavior": "OPTIONAL"
          },
          "audience": {
            "type": "string",
            "description": "Who the author's own page is for, with the values of a post's `audience`. It hides the author's page, their place in the author list and their byline from other readers; the posts they wrote stay as visible as they are, shown without the byline.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "display_name",
          "slug",
          "is_active"
        ],
        "examples": [
          {
            "display_name": "string",
            "slug": "string",
            "is_active": true
          }
        ]
      },
      "BlogAuthorUpdate": {
        "type": "object",
        "description": "The `blog_authors` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the author is shown on the site. It is one of the two fields a view cannot override, so an author is hidden everywhere or nowhere.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "bio": {
            "type": "string",
            "description": "The short biography rendered under the byline and on the author's own page.",
            "x-field-behavior": "OPTIONAL"
          },
          "avatar_media_id": {
            "type": "string",
            "description": "The `media` resource used as the author's portrait.",
            "x-field-behavior": "OPTIONAL"
          },
          "audience": {
            "type": "string",
            "description": "Who the author's own page is for, with the values of a post's `audience`. It hides the author's page, their place in the author list and their byline from other readers; the posts they wrote stay as visible as they are, shown without the byline.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "examples": [
          {
            "display_name": "string",
            "slug": "string",
            "is_active": true
          }
        ]
      },
      "BlogAuthorView": {
        "type": "object",
        "description": "What one view says instead of the master author: the name in the byline, the biography and the URL segment. The portrait and `is_active` stay on the author itself.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_authors/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "blog_author_id": {
            "type": "string",
            "description": "The resource this overlay belongs to. Fixed by the URL \u2014 an overlay cannot change master.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "bio": {
            "type": "string",
            "description": "This view's biography for the author.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the author's page.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_authors/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "blog_author_id": "string",
            "view_id": "string",
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string",
            "bio": "string",
            "slug": "string"
          }
        ]
      },
      "BlogAuthorViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "bio": {
            "type": "string",
            "description": "This view's biography for the author.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the author's page.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string"
          }
        ]
      },
      "BlogAuthorViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "bio": {
            "type": "string",
            "description": "This view's biography for the author.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the author's page.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string"
          }
        ]
      },
      "BlogCategory": {
        "type": "object",
        "description": "A section of the blog. Categories form a tree: `parent_id` names the one above, `path` and `url_path` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. `:set_posts` replaces the posts of one category in a single call.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_categories/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "parent_id": {
            "type": "string",
            "description": "The category this one hangs under; empty at the root. Settable on create and immutable afterwards \u2014 moving a category is `:move`, which recomputes the whole subtree.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true
          },
          "path": {
            "type": "string",
            "description": "The category's position in the tree: the ids of its ancestors and its own, in order. Sorting by it is what renders a whole tree in one page.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true
          },
          "url_path": {
            "type": "string",
            "description": "The category's full URL path on the live site \u2014 its own slug behind the slugs of its ancestors.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "guides/packing"
            ]
          },
          "level": {
            "type": "integer",
            "format": "int64",
            "description": "How deep the category sits, counting the root as 0. Server-maintained, like the rest of the tree bookkeeping.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The category's position among its siblings. Set by `:move`, never by a write.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true
          },
          "description": {
            "type": "string",
            "description": "The blurb rendered on the category's own page.",
            "x-field-behavior": "OPTIONAL"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the category is shown. Hiding one hides its whole subtree on the site.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this category appears in. Empty means every view, not none.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the category is for, with the values of a post's `audience`. It narrows the whole subtree: a subcategory, and every post in the category or below it, reaches only readers this category is for too \u2014 the strictest audience on the way up wins. A category not everybody may read is left out of the sitemap, the menus of anonymous visitors and every cached copy of the blog.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_categories/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "string",
            "slug": "string",
            "parent_id": "string",
            "path": "string",
            "url_path": "guides/packing",
            "level": 0,
            "sort_order": 0,
            "description": "string",
            "is_active": true,
            "visible_view_ids": [],
            "audience": "GROUPS",
            "customer_group_ids": [
              "6a5e4957db9aab43d50bfd35"
            ]
          }
        ]
      },
      "BlogCategoryCreate": {
        "type": "object",
        "description": "The `blog_categories` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "parent_id": {
            "type": "string",
            "description": "The category this one hangs under; empty at the root. Settable on create and immutable afterwards \u2014 moving a category is `:move`, which recomputes the whole subtree.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true
          },
          "description": {
            "type": "string",
            "description": "The blurb rendered on the category's own page.",
            "x-field-behavior": "OPTIONAL"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the category is shown. Hiding one hides its whole subtree on the site.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this category appears in. Empty means every view, not none.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the category is for, with the values of a post's `audience`. It narrows the whole subtree: a subcategory, and every post in the category or below it, reaches only readers this category is for too \u2014 the strictest audience on the way up wins. A category not everybody may read is left out of the sitemap, the menus of anonymous visitors and every cached copy of the blog.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "display_name",
          "slug",
          "is_active"
        ],
        "examples": [
          {
            "display_name": "string",
            "slug": "string",
            "is_active": true
          }
        ]
      },
      "BlogCategoryUpdate": {
        "type": "object",
        "description": "The `blog_categories` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "description": {
            "type": "string",
            "description": "The blurb rendered on the category's own page.",
            "x-field-behavior": "OPTIONAL"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the category is shown. Hiding one hides its whole subtree on the site.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this category appears in. Empty means every view, not none.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the category is for, with the values of a post's `audience`. It narrows the whole subtree: a subcategory, and every post in the category or below it, reaches only readers this category is for too \u2014 the strictest audience on the way up wins. A category not everybody may read is left out of the sitemap, the menus of anonymous visitors and every cached copy of the blog.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "examples": [
          {
            "display_name": "string",
            "slug": "string",
            "is_active": true
          }
        ]
      },
      "BlogCategoryView": {
        "type": "object",
        "description": "What one view says instead of the master category: its name, its blurb and its URL segment. The shape of the tree is not overridable \u2014 a category has the same parent and the same siblings in every view.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_categories/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "blog_category_id": {
            "type": "string",
            "description": "The resource this overlay belongs to. Fixed by the URL \u2014 an overlay cannot change master.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "description": {
            "type": "string",
            "description": "This view's blurb for the category.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the category, so a translated section gets a translated URL.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_categories/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "blog_category_id": "string",
            "view_id": "string",
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string",
            "description": "string",
            "slug": "string"
          }
        ]
      },
      "BlogCategoryViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "description": {
            "type": "string",
            "description": "This view's blurb for the category.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the category, so a translated section gets a translated URL.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string"
          }
        ]
      },
      "BlogCategoryViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "description": {
            "type": "string",
            "description": "This view's blurb for the category.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the category, so a translated section gets a translated URL.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string"
          }
        ]
      },
      "BlogPost": {
        "type": "object",
        "description": "One article of the website's blog: headline, slug, teaser, rich-text body, byline and dates, plus the categories and tags it belongs to. What a view says instead lives in its `views` overlay, and a post is live when `is_active` is true and `publish_time` has passed.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_posts/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "title": {
            "type": "string",
            "description": "The post's headline, and the label the admin lists it under.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "How we pack a piano"
            ]
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the post is published. Together with `publish_time` it decides what the live blog shows: an inactive post is never rendered, however old its publish time.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "author_id": {
            "type": "string",
            "description": "The `blog_authors` resource shown as the byline.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "excerpt": {
            "type": "string",
            "description": "The short teaser used in listings and cards. Plain text, not the first paragraph of `content`.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The post body as rich-text HTML, with `entity://` links resolved per view when the page is rendered.",
            "x-field-behavior": "OPTIONAL"
          },
          "featured_image_media_id": {
            "type": "string",
            "description": "The `media` resource used as the post's lead image, in listings and as the social-card picture.",
            "x-field-behavior": "OPTIONAL"
          },
          "publish_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the post is dated on the site. A time in the future keeps it out of the live blog until then, which is how a post is scheduled.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          },
          "meta_title": {
            "type": "string",
            "description": "The `<title>` of the rendered post. Falls back to `title` when empty.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The meta description of the rendered post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The meta keywords of the rendered post.",
            "x-field-behavior": "OPTIONAL"
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this post appears in. Empty means every view, not none.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the post is for. `PUBLIC` \u2014 everybody, the default. `AUTHENTICATED` \u2014 the website's signed-in customers. `GROUPS` \u2014 the customers in at least one of `customer_group_ids`. A reader sees the post only if it is for them and so is every category it is in, with each category's ancestors: the strictest wins. A post not everybody may read is left out of the sitemap, the feeds, the site search, the public API and every cached copy of the blog.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The categories this post belongs to. Filled in on a read of one post and on a write; a List leaves it out, because membership is a join and a page of posts would be a page of joins.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The tags on this post, with the same read rule as `category_ids`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_posts/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "title": "How we pack a piano",
            "slug": "string",
            "is_active": true,
            "author_id": "string",
            "excerpt": "string",
            "content": "string",
            "featured_image_media_id": "string",
            "publish_time": "2026-01-15T09:30:00Z",
            "meta_title": "string",
            "meta_description": "string",
            "meta_keywords": "string",
            "visible_view_ids": [],
            "audience": "GROUPS",
            "customer_group_ids": [
              "6a5e4957db9aab43d50bfd35"
            ],
            "category_ids": [],
            "tag_ids": []
          }
        ]
      },
      "BlogPostCreate": {
        "type": "object",
        "description": "The `blog_posts` fields a client may set on create.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The post's headline, and the label the admin lists it under.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "How we pack a piano"
            ]
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the post is published. Together with `publish_time` it decides what the live blog shows: an inactive post is never rendered, however old its publish time.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "author_id": {
            "type": "string",
            "description": "The `blog_authors` resource shown as the byline.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "excerpt": {
            "type": "string",
            "description": "The short teaser used in listings and cards. Plain text, not the first paragraph of `content`.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The post body as rich-text HTML, with `entity://` links resolved per view when the page is rendered.",
            "x-field-behavior": "OPTIONAL"
          },
          "featured_image_media_id": {
            "type": "string",
            "description": "The `media` resource used as the post's lead image, in listings and as the social-card picture.",
            "x-field-behavior": "OPTIONAL"
          },
          "publish_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the post is dated on the site. A time in the future keeps it out of the live blog until then, which is how a post is scheduled.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          },
          "meta_title": {
            "type": "string",
            "description": "The `<title>` of the rendered post. Falls back to `title` when empty.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The meta description of the rendered post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The meta keywords of the rendered post.",
            "x-field-behavior": "OPTIONAL"
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this post appears in. Empty means every view, not none.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the post is for. `PUBLIC` \u2014 everybody, the default. `AUTHENTICATED` \u2014 the website's signed-in customers. `GROUPS` \u2014 the customers in at least one of `customer_group_ids`. A reader sees the post only if it is for them and so is every category it is in, with each category's ancestors: the strictest wins. A post not everybody may read is left out of the sitemap, the feeds, the site search, the public API and every cached copy of the blog.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The categories this post belongs to. Filled in on a read of one post and on a write; a List leaves it out, because membership is a join and a page of posts would be a page of joins.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The tags on this post, with the same read rule as `category_ids`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "required": [
          "title",
          "slug",
          "is_active"
        ],
        "examples": [
          {
            "title": "How we pack a piano",
            "slug": "string",
            "is_active": true
          }
        ]
      },
      "BlogPostUpdate": {
        "type": "object",
        "description": "The `blog_posts` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The post's headline, and the label the admin lists it under.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "How we pack a piano"
            ]
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the post is published. Together with `publish_time` it decides what the live blog shows: an inactive post is never rendered, however old its publish time.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "author_id": {
            "type": "string",
            "description": "The `blog_authors` resource shown as the byline.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "excerpt": {
            "type": "string",
            "description": "The short teaser used in listings and cards. Plain text, not the first paragraph of `content`.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The post body as rich-text HTML, with `entity://` links resolved per view when the page is rendered.",
            "x-field-behavior": "OPTIONAL"
          },
          "featured_image_media_id": {
            "type": "string",
            "description": "The `media` resource used as the post's lead image, in listings and as the social-card picture.",
            "x-field-behavior": "OPTIONAL"
          },
          "publish_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the post is dated on the site. A time in the future keeps it out of the live blog until then, which is how a post is scheduled.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          },
          "meta_title": {
            "type": "string",
            "description": "The `<title>` of the rendered post. Falls back to `title` when empty.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The meta description of the rendered post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The meta keywords of the rendered post.",
            "x-field-behavior": "OPTIONAL"
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this post appears in. Empty means every view, not none.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the post is for. `PUBLIC` \u2014 everybody, the default. `AUTHENTICATED` \u2014 the website's signed-in customers. `GROUPS` \u2014 the customers in at least one of `customer_group_ids`. A reader sees the post only if it is for them and so is every category it is in, with each category's ancestors: the strictest wins. A post not everybody may read is left out of the sitemap, the feeds, the site search, the public API and every cached copy of the blog.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The categories this post belongs to. Filled in on a read of one post and on a write; a List leaves it out, because membership is a join and a page of posts would be a page of joins.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The tags on this post, with the same read rule as `category_ids`.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "examples": [
          {
            "title": "How we pack a piano",
            "slug": "string",
            "is_active": true
          }
        ]
      },
      "BlogPostView": {
        "type": "object",
        "description": "What one view says instead of the master post \u2014 headline, slug, teaser, body, SEO metadata and lead image. Every field falls back to the post, and `overridden` decides which of them this view claims.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_posts/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "blog_post_id": {
            "type": "string",
            "description": "The resource this overlay belongs to. Fixed by the URL \u2014 an overlay cannot change master.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's headline for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "excerpt": {
            "type": "string",
            "description": "This view's teaser for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "This view's `<title>` for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "This view's meta description for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "This view's meta keywords for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "featured_image_media_id": {
            "type": "string",
            "description": "This view's lead image for the post, for a picture carrying text that has to be translated too.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_posts/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "blog_post_id": "string",
            "view_id": "string",
            "overridden": [
              "display_name",
              "slug"
            ],
            "title": "string",
            "slug": "string",
            "excerpt": "string",
            "content": "string",
            "meta_title": "string",
            "meta_description": "string",
            "meta_keywords": "string",
            "featured_image_media_id": "string"
          }
        ]
      },
      "BlogPostViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's headline for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "excerpt": {
            "type": "string",
            "description": "This view's teaser for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "This view's `<title>` for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "This view's meta description for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "This view's meta keywords for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "featured_image_media_id": {
            "type": "string",
            "description": "This view's lead image for the post, for a picture carrying text that has to be translated too.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "title": "string"
          }
        ]
      },
      "BlogPostViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's headline for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "excerpt": {
            "type": "string",
            "description": "This view's teaser for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "This view's `<title>` for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "This view's meta description for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "This view's meta keywords for the post.",
            "x-field-behavior": "OPTIONAL"
          },
          "featured_image_media_id": {
            "type": "string",
            "description": "This view's lead image for the post, for a picture carrying text that has to be translated too.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "title": "string"
          }
        ]
      },
      "BlogTag": {
        "type": "object",
        "description": "A flat label a post can carry \u2014 the cross-cutting counterpart of a category, which is a place in a tree. A tag is two fields and its per-view overlay; posts are attached from the post's own `tag_ids`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_tags/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the tag's own page is for, with the values of a post's `audience`. It hides the tag's archive and the tag itself on shared surfaces \u2014 the tag list, a post's tag chips \u2014 from other readers; it never hides a post that carries the tag.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_tags/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "string",
            "slug": "string",
            "audience": "GROUPS",
            "customer_group_ids": [
              "6a5e4957db9aab43d50bfd35"
            ]
          }
        ]
      },
      "BlogTagCreate": {
        "type": "object",
        "description": "The `blog_tags` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the tag's own page is for, with the values of a post's `audience`. It hides the tag's archive and the tag itself on shared surfaces \u2014 the tag list, a post's tag chips \u2014 from other readers; it never hides a post that carries the tag.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "display_name",
          "slug"
        ],
        "examples": [
          {
            "display_name": "string",
            "slug": "string"
          }
        ]
      },
      "BlogTagUpdate": {
        "type": "object",
        "description": "The `blog_tags` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name this is shown under, on the site and in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "slug": {
            "type": "string",
            "description": "The URL segment this is addressed by on the live site. Unique among its siblings, and a view may override it so a translated page gets a translated URL.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the tag's own page is for, with the values of a post's `audience`. It hides the tag's archive and the tag itself on shared surfaces \u2014 the tag list, a post's tag chips \u2014 from other readers; it never hides a post that carries the tag.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` audience is for \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "examples": [
          {
            "display_name": "string",
            "slug": "string"
          }
        ]
      },
      "BlogTagView": {
        "type": "object",
        "description": "What one view says instead of the master tag: its name and its URL segment. Which posts carry the tag is not a per-view decision.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/blog_tags/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "blog_tag_id": {
            "type": "string",
            "description": "The resource this overlay belongs to. Fixed by the URL \u2014 an overlay cannot change master.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the tag.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/blog_tags/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "blog_tag_id": "string",
            "view_id": "string",
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string",
            "slug": "string"
          }
        ]
      },
      "BlogTagViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the tag.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string"
          }
        ]
      },
      "BlogTagViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty value with the field absent from this list means \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "display_name",
                "slug"
              ]
            ]
          },
          "display_name": {
            "type": "string",
            "description": "This view's name for the resource.",
            "x-field-behavior": "OPTIONAL"
          },
          "slug": {
            "type": "string",
            "description": "This view's URL segment for the tag.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "display_name",
              "slug"
            ],
            "display_name": "string"
          }
        ]
      },
      "CmsBlock": {
        "type": "object",
        "description": "A reusable fragment of content, addressed by its `identifier` and pulled into pages, themes and smart links rather than into a URL of its own. Footers, contact strips, banners \u2014 anything that has to say the same thing in several places and change in one.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/cms_blocks/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "title": {
            "type": "string",
            "description": "The block's label in the admin. Never rendered on the site \u2014 the block is its content.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Footer contacts"
            ]
          },
          "identifier": {
            "type": "string",
            "description": "The handle a page, a theme or a smart link pulls this block in by. Unique per website, and the one field worth keeping stable.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "footer-contacts"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the block renders. An inactive block is left out wherever it is referenced.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "content": {
            "type": "string",
            "description": "The fragment itself, as rich-text HTML.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "<p>Mon\u2013Fri, 9:00\u201318:00</p>"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/cms_blocks/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "title": "Footer contacts",
            "identifier": "footer-contacts",
            "is_active": true,
            "content": "<p>Mon\u2013Fri, 9:00\u201318:00</p>"
          }
        ]
      },
      "CmsBlockCreate": {
        "type": "object",
        "description": "The `cms_blocks` fields a client may set on create.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The block's label in the admin. Never rendered on the site \u2014 the block is its content.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Footer contacts"
            ]
          },
          "identifier": {
            "type": "string",
            "description": "The handle a page, a theme or a smart link pulls this block in by. Unique per website, and the one field worth keeping stable.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "footer-contacts"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the block renders. An inactive block is left out wherever it is referenced.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "content": {
            "type": "string",
            "description": "The fragment itself, as rich-text HTML.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "<p>Mon\u2013Fri, 9:00\u201318:00</p>"
            ]
          }
        },
        "required": [
          "title",
          "identifier",
          "is_active"
        ],
        "examples": [
          {
            "title": "Footer contacts",
            "identifier": "footer-contacts",
            "is_active": true
          }
        ]
      },
      "CmsBlockUpdate": {
        "type": "object",
        "description": "The `cms_blocks` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The block's label in the admin. Never rendered on the site \u2014 the block is its content.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Footer contacts"
            ]
          },
          "identifier": {
            "type": "string",
            "description": "The handle a page, a theme or a smart link pulls this block in by. Unique per website, and the one field worth keeping stable.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "footer-contacts"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the block renders. An inactive block is left out wherever it is referenced.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "content": {
            "type": "string",
            "description": "The fragment itself, as rich-text HTML.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "<p>Mon\u2013Fri, 9:00\u201318:00</p>"
            ]
          }
        },
        "examples": [
          {
            "title": "Footer contacts",
            "identifier": "footer-contacts",
            "is_active": true
          }
        ]
      },
      "CmsBlockView": {
        "type": "object",
        "description": "What one view says instead of the master block. A block has one field worth translating, so this is the smallest overlay in the API \u2014 but it works exactly like the others: optional fields, a fallback to the master, and `overridden` deciding which of them this view claims.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/cms_blocks/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "cms_block_id": {
            "type": "string",
            "description": "The block this overlay belongs to. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides \u2014 here, at most `content`. A field not listed falls back to the block.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "content"
              ]
            ]
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the block.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/cms_blocks/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "cms_block_id": "string",
            "view_id": "string",
            "overridden": [
              "content"
            ],
            "content": "string"
          }
        ]
      },
      "CmsBlockViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides \u2014 here, at most `content`. A field not listed falls back to the block.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "content"
              ]
            ]
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the block.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "content"
            ],
            "content": "string"
          }
        ]
      },
      "CmsBlockViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides \u2014 here, at most `content`. A field not listed falls back to the block.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "content"
              ]
            ]
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the block.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "content"
            ],
            "content": "string"
          }
        ]
      },
      "CmsPageGroupVersion": {
        "type": "object",
        "description": "What the customers of one group see of a page instead of the page itself: its text, its title, its hero \u2014 a price or a condition meant for them. A signed-in customer in several groups that each have a version sees the version of the group with the highest `priority`; everybody else, the page. A version is the same on every view, and never changes where the page lives or who may read it.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/cms_pages/9c2d40f7e1ab/group_versions/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "cms_page_id": {
            "type": "string",
            "description": "The page this is a version of. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "customer_group_id": {
            "type": "string",
            "description": "The customer group this version is for \u2014 a group of the same website, one version per group on a page. Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "65aa00000000000000000001"
            ]
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the page fields this version replaces, out of `title`, `content`, `meta_title`, `meta_description`, `meta_keywords`, `background_media_id` and `background_position`. A field not listed here is the page's own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "content"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "The group's title for the page. Not blank while `title` is overridden.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The group's rich-text body for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "The group's `<title>` for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The group's meta description for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The group's meta keywords for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_media_id": {
            "type": "string",
            "description": "The group's hero image for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "The group's anchor for the hero image.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/cms_pages/9c2d40f7e1ab/group_versions/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "cms_page_id": "string",
            "customer_group_id": "65aa00000000000000000001",
            "overridden": [
              "content"
            ],
            "title": "string",
            "content": "string",
            "meta_title": "string",
            "meta_description": "string",
            "meta_keywords": "string",
            "background_media_id": "string",
            "background_position": "string"
          }
        ]
      },
      "CmsPageGroupVersionCreate": {
        "type": "object",
        "description": "The `group_versions` fields a client may set on create.",
        "properties": {
          "customer_group_id": {
            "type": "string",
            "description": "The customer group this version is for \u2014 a group of the same website, one version per group on a page. Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "65aa00000000000000000001"
            ]
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the page fields this version replaces, out of `title`, `content`, `meta_title`, `meta_description`, `meta_keywords`, `background_media_id` and `background_position`. A field not listed here is the page's own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "content"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "The group's title for the page. Not blank while `title` is overridden.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The group's rich-text body for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "The group's `<title>` for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The group's meta description for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The group's meta keywords for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_media_id": {
            "type": "string",
            "description": "The group's hero image for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "The group's anchor for the hero image.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "customer_group_id": "65aa00000000000000000001",
            "overridden": [
              "content"
            ]
          }
        ]
      },
      "CmsPageGroupVersionUpdate": {
        "type": "object",
        "description": "The `group_versions` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the page fields this version replaces, out of `title`, `content`, `meta_title`, `meta_description`, `meta_keywords`, `background_media_id` and `background_position`. A field not listed here is the page's own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "content"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "The group's title for the page. Not blank while `title` is overridden.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The group's rich-text body for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "The group's `<title>` for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The group's meta description for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The group's meta keywords for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_media_id": {
            "type": "string",
            "description": "The group's hero image for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "The group's anchor for the hero image.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "content"
            ],
            "title": "string"
          }
        ]
      },
      "CmsPage": {
        "type": "object",
        "description": "A page of the site \u2014 its title, its slug, its rich-text body and its SEO metadata. A page is one resource for the whole website: what one view says instead of the master lives in its `views` overlay, and which views show it at all is `visible_view_ids`. Which visitors may read it is `audience`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/cms_pages/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "title": {
            "type": "string",
            "description": "The page's heading, and the label the admin lists it under.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "About us"
            ]
          },
          "url_key": {
            "type": "string",
            "description": "The page's slug \u2014 the last segment of its URL on the live site. Unique per view.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "about-us"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the page is published. An inactive page stays in the admin and 404s on the site.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "meta_title": {
            "type": "string",
            "description": "The `<title>` of the rendered page. Falls back to `title` when empty.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The `<meta name=\"description\">` of the rendered page, and what a search engine usually shows under the link.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The `<meta name=\"keywords\">` of the rendered page. Kept for sites that still fill it in.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The page body as rich-text HTML. Links to other resources may be written as `entity://` URLs, which the renderer resolves to the right URL for the view it is rendering.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "<h2>Since 1994</h2><p>We move things.</p>"
            ]
          },
          "background_media_id": {
            "type": "string",
            "description": "The `media` resource used as the page's hero image. Empty means the theme decides.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "Where the hero image is anchored when it is cropped to the banner \u2014 a CSS `background-position` value such as `center top`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "center top"
            ]
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this page appears in. **Empty means every view**, not none \u2014 a page is visible everywhere until it is restricted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the page is for. `PUBLIC` \u2014 everybody, the default. `AUTHENTICATED` \u2014 the website's signed-in customers. `GROUPS` \u2014 the customers in at least one of `customer_group_ids`. A page that is not `PUBLIC` is left out of the sitemap, the site search, the public API and every cached copy of the site, and is rendered only for a visitor it is for.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` page is shown to \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          },
          "view_id": {
            "type": "string",
            "description": "Deprecated. Pages used to be duplicated per view; a page is now one master resource with an overlay per view, so this is empty on everything written since. Use `views` and `visible_view_ids`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "canonical_id": {
            "type": "string",
            "description": "Deprecated companion of `view_id`: which master a duplicated legacy page belonged to.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/cms_pages/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "title": "About us",
            "url_key": "about-us",
            "is_active": true,
            "meta_title": "string",
            "meta_description": "string",
            "meta_keywords": "string",
            "content": "<h2>Since 1994</h2><p>We move things.</p>",
            "background_media_id": "string",
            "background_position": "center top",
            "visible_view_ids": [],
            "audience": "GROUPS",
            "customer_group_ids": [
              "6a5e4957db9aab43d50bfd35"
            ],
            "view_id": "string",
            "canonical_id": "string"
          }
        ]
      },
      "CmsPageCreate": {
        "type": "object",
        "description": "The `cms_pages` fields a client may set on create.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The page's heading, and the label the admin lists it under.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "About us"
            ]
          },
          "url_key": {
            "type": "string",
            "description": "The page's slug \u2014 the last segment of its URL on the live site. Unique per view.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "about-us"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the page is published. An inactive page stays in the admin and 404s on the site.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "meta_title": {
            "type": "string",
            "description": "The `<title>` of the rendered page. Falls back to `title` when empty.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The `<meta name=\"description\">` of the rendered page, and what a search engine usually shows under the link.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The `<meta name=\"keywords\">` of the rendered page. Kept for sites that still fill it in.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The page body as rich-text HTML. Links to other resources may be written as `entity://` URLs, which the renderer resolves to the right URL for the view it is rendering.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "<h2>Since 1994</h2><p>We move things.</p>"
            ]
          },
          "background_media_id": {
            "type": "string",
            "description": "The `media` resource used as the page's hero image. Empty means the theme decides.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "Where the hero image is anchored when it is cropped to the banner \u2014 a CSS `background-position` value such as `center top`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "center top"
            ]
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this page appears in. **Empty means every view**, not none \u2014 a page is visible everywhere until it is restricted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the page is for. `PUBLIC` \u2014 everybody, the default. `AUTHENTICATED` \u2014 the website's signed-in customers. `GROUPS` \u2014 the customers in at least one of `customer_group_ids`. A page that is not `PUBLIC` is left out of the sitemap, the site search, the public API and every cached copy of the site, and is rendered only for a visitor it is for.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` page is shown to \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "required": [
          "title",
          "url_key",
          "is_active"
        ],
        "examples": [
          {
            "title": "About us",
            "url_key": "about-us",
            "is_active": true
          }
        ]
      },
      "CmsPageUpdate": {
        "type": "object",
        "description": "The `cms_pages` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The page's heading, and the label the admin lists it under.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "About us"
            ]
          },
          "url_key": {
            "type": "string",
            "description": "The page's slug \u2014 the last segment of its URL on the live site. Unique per view.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "about-us"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the page is published. An inactive page stays in the admin and 404s on the site.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "meta_title": {
            "type": "string",
            "description": "The `<title>` of the rendered page. Falls back to `title` when empty.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "The `<meta name=\"description\">` of the rendered page, and what a search engine usually shows under the link.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "The `<meta name=\"keywords\">` of the rendered page. Kept for sites that still fill it in.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "The page body as rich-text HTML. Links to other resources may be written as `entity://` URLs, which the renderer resolves to the right URL for the view it is rendering.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "<h2>Since 1994</h2><p>We move things.</p>"
            ]
          },
          "background_media_id": {
            "type": "string",
            "description": "The `media` resource used as the page's hero image. Empty means the theme decides.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "Where the hero image is anchored when it is cropped to the banner \u2014 a CSS `background-position` value such as `center top`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "center top"
            ]
          },
          "visible_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views this page appears in. **Empty means every view**, not none \u2014 a page is visible everywhere until it is restricted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "audience": {
            "type": "string",
            "description": "Who the page is for. `PUBLIC` \u2014 everybody, the default. `AUTHENTICATED` \u2014 the website's signed-in customers. `GROUPS` \u2014 the customers in at least one of `customer_group_ids`. A page that is not `PUBLIC` is left out of the sitemap, the site search, the public API and every cached copy of the site, and is rendered only for a visitor it is for.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "GROUPS"
            ]
          },
          "customer_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `customer_groups` of the website a `GROUPS` page is shown to \u2014 at least one, at most 100. Empty for any other audience: setting the audience to anything else empties it, and a deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "6a5e4957db9aab43d50bfd35"
              ]
            ]
          }
        },
        "examples": [
          {
            "title": "About us",
            "url_key": "about-us",
            "is_active": true
          }
        ]
      },
      "CmsPageView": {
        "type": "object",
        "description": "What one view says instead of the master page. Every field here is optional and every one of them falls back to the page itself; `overridden` is the list that decides which of them this view actually claims. The collection is bounded by the number of views on the website and is served whole.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/cms_pages/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "cms_page_id": {
            "type": "string",
            "description": "The page this overlay belongs to. Fixed by the URL \u2014 an overlay cannot change master.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty string in `title` with `title` absent from this list is \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "title",
                "content"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's title for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "url_key": {
            "type": "string",
            "description": "This view's slug for the page, so a translated page can have a translated URL.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "This view's `<title>` for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "This view's meta description for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "This view's meta keywords for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_media_id": {
            "type": "string",
            "description": "This view's hero image for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "This view's anchor for the hero image.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/cms_pages/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "cms_page_id": "string",
            "view_id": "string",
            "overridden": [
              "title",
              "content"
            ],
            "title": "string",
            "url_key": "string",
            "content": "string",
            "meta_title": "string",
            "meta_description": "string",
            "meta_keywords": "string",
            "background_media_id": "string",
            "background_position": "string"
          }
        ]
      },
      "CmsPageViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty string in `title` with `title` absent from this list is \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "title",
                "content"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's title for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "url_key": {
            "type": "string",
            "description": "This view's slug for the page, so a translated page can have a translated URL.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "This view's `<title>` for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "This view's meta description for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "This view's meta keywords for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_media_id": {
            "type": "string",
            "description": "This view's hero image for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "This view's anchor for the hero image.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "title",
              "content"
            ],
            "title": "string"
          }
        ]
      },
      "CmsPageViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field counts as overridden only while it is listed here \u2014 an empty string in `title` with `title` absent from this list is \"use the master\", not \"show nothing\".",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "title",
                "content"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's title for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "url_key": {
            "type": "string",
            "description": "This view's slug for the page, so a translated page can have a translated URL.",
            "x-field-behavior": "OPTIONAL"
          },
          "content": {
            "type": "string",
            "description": "This view's rich-text body for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_title": {
            "type": "string",
            "description": "This view's `<title>` for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_description": {
            "type": "string",
            "description": "This view's meta description for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "meta_keywords": {
            "type": "string",
            "description": "This view's meta keywords for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_media_id": {
            "type": "string",
            "description": "This view's hero image for the page.",
            "x-field-behavior": "OPTIONAL"
          },
          "background_position": {
            "type": "string",
            "description": "This view's anchor for the hero image.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "title",
              "content"
            ],
            "title": "string"
          }
        ]
      },
      "CustomerAttributeGroup": {
        "type": "object",
        "description": "A section the customer form in the admin gathers customer attributes under \u2014 \u00abPersonal\u00bb, \u00abPreferences\u00bb. An attribute names its section in `group_id`; the registration form on the site lists its fields flat and ignores sections. Deleting a section moves its attributes to the default one. At most 20 per website.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/customer_attribute_groups/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The section's heading, shown wherever `labels` has none for the locale. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Preferences"
            ]
          },
          "labels": {
            "description": "The heading in other languages: an object from a locale (`de`, `pt-BR`) to the heading in it, each at most 255 characters. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "de": "Einstellungen"
              }
            ]
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "Where the section stands among the website's sections: they are shown in ascending `sort_order`. A new section comes last; `:move` is the only way to change it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true,
            "examples": [
              10
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/customer_attribute_groups/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Preferences",
            "labels": {
              "de": "Einstellungen"
            },
            "sort_order": 10
          }
        ]
      },
      "CustomerAttributeGroupCreate": {
        "type": "object",
        "description": "The `customer_attribute_groups` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The section's heading, shown wherever `labels` has none for the locale. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Preferences"
            ]
          },
          "labels": {
            "description": "The heading in other languages: an object from a locale (`de`, `pt-BR`) to the heading in it, each at most 255 characters. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "de": "Einstellungen"
              }
            ]
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Preferences"
          }
        ]
      },
      "CustomerAttributeGroupUpdate": {
        "type": "object",
        "description": "The `customer_attribute_groups` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The section's heading, shown wherever `labels` has none for the locale. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Preferences"
            ]
          },
          "labels": {
            "description": "The heading in other languages: an object from a locale (`de`, `pt-BR`) to the heading in it, each at most 255 characters. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "de": "Einstellungen"
              }
            ]
          }
        },
        "examples": [
          {
            "display_name": "Preferences"
          }
        ]
      },
      "CustomerAttribute": {
        "type": "object",
        "description": "A field the tenant adds to the website's customers \u2014 a birth date, a loyalty number, a preferred store \u2014 with its type, its label in each language, whether it is required and whether the registration form asks for it. A customer's values are kept in their `attributes` under the field's `key`. A field is switched off with `is_active` rather than deleted when its values are worth keeping: deleting it removes them from every customer. At most 100 per website.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/customer_attributes/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "key": {
            "type": "string",
            "description": "The name a customer's value is stored under in their `attributes`, and the name a registration form sends it as: a lowercase letter, then up to 63 lowercase letters, digits and underscores. Unique on the website, and none of a customer's own field names (`email`, `display_name`, `tags`, ...). Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "birth_date"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The field's label, shown wherever `labels` has none for the locale. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Date of birth"
            ]
          },
          "labels": {
            "description": "The label in other languages: an object from a locale (`de`, `pt-BR`) to the label in it, each at most 255 characters. A locale it leaves out shows `display_name`. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "de": "Geburtsdatum"
              }
            ]
          },
          "description": {
            "type": "string",
            "description": "The hint shown under the field on a form. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "We send you a gift on your birthday."
            ]
          },
          "type": {
            "type": "string",
            "description": "What the field holds, and so which control a form draws: `TEXT`, `TEXTAREA`, `NUMBER`, `BOOLEAN`, `DATE` (a `YYYY-MM-DD` string), `SELECT` (one of `options`) or `MULTISELECT` (any of them). Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "DATE"
            ]
          },
          "options": {
            "description": "The choices of a `SELECT` or `MULTISELECT` field, in the order a form lists them: each `{value, display_name, labels}`, where `value` is what a customer's `attributes` stores and is unique within the field. At least one and at most 100 for those two types, none for the others. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "value": "store_a",
                  "display_name": "Store A"
                }
              ]
            ]
          },
          "is_required": {
            "type": "boolean",
            "description": "Whether a form refuses to save the customer without a value for it. `false` when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "show_in_registration": {
            "type": "boolean",
            "description": "Whether the website's registration form asks for it. `false` when omitted \u2014 the field is then filled in the admin only.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the field is in use. Switching it off takes it off every form and stops new values being accepted, while the values customers already hold stay readable \u2014 the way to retire a field without losing them. `true` when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "min_length": {
            "type": "integer",
            "format": "int64",
            "description": "The fewest characters a `TEXT` or `TEXTAREA` value may have. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          },
          "max_length": {
            "type": "integer",
            "format": "int64",
            "description": "The most characters a `TEXT` or `TEXTAREA` value may have \u2014 at most 1024 for `TEXT` and 8192 for `TEXTAREA`, which is also the limit when it is omitted. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              120
            ]
          },
          "min_value": {
            "type": "number",
            "format": "double",
            "description": "The smallest value a `NUMBER` field accepts. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              0
            ]
          },
          "max_value": {
            "type": "number",
            "format": "double",
            "description": "The largest value a `NUMBER` field accepts. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              100
            ]
          },
          "group_id": {
            "type": "string",
            "description": "The `customer_attribute_groups` section the admin's customer form shows the field in \u2014 an id of a group of the website. Without one the field is in the default section; deleting its group puts it back there.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "Where the field stands among the website's fields: lists and forms show them in ascending `sort_order`. A new field comes last; `:move` is the only way to change it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true,
            "examples": [
              10
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/customer_attributes/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "key": "birth_date",
            "display_name": "Date of birth",
            "labels": {
              "de": "Geburtsdatum"
            },
            "description": "We send you a gift on your birthday.",
            "type": "DATE",
            "options": [
              {
                "value": "store_a",
                "display_name": "Store A"
              }
            ],
            "is_required": true,
            "show_in_registration": true,
            "is_active": true,
            "min_length": 2,
            "max_length": 120,
            "min_value": 0,
            "max_value": 100,
            "group_id": "string",
            "sort_order": 10
          }
        ]
      },
      "CustomerAttributeCreate": {
        "type": "object",
        "description": "The `customer_attributes` fields a client may set on create.",
        "properties": {
          "key": {
            "type": "string",
            "description": "The name a customer's value is stored under in their `attributes`, and the name a registration form sends it as: a lowercase letter, then up to 63 lowercase letters, digits and underscores. Unique on the website, and none of a customer's own field names (`email`, `display_name`, `tags`, ...). Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "birth_date"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The field's label, shown wherever `labels` has none for the locale. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Date of birth"
            ]
          },
          "labels": {
            "description": "The label in other languages: an object from a locale (`de`, `pt-BR`) to the label in it, each at most 255 characters. A locale it leaves out shows `display_name`. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "de": "Geburtsdatum"
              }
            ]
          },
          "description": {
            "type": "string",
            "description": "The hint shown under the field on a form. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "We send you a gift on your birthday."
            ]
          },
          "type": {
            "type": "string",
            "description": "What the field holds, and so which control a form draws: `TEXT`, `TEXTAREA`, `NUMBER`, `BOOLEAN`, `DATE` (a `YYYY-MM-DD` string), `SELECT` (one of `options`) or `MULTISELECT` (any of them). Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "DATE"
            ]
          },
          "options": {
            "description": "The choices of a `SELECT` or `MULTISELECT` field, in the order a form lists them: each `{value, display_name, labels}`, where `value` is what a customer's `attributes` stores and is unique within the field. At least one and at most 100 for those two types, none for the others. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "value": "store_a",
                  "display_name": "Store A"
                }
              ]
            ]
          },
          "is_required": {
            "type": "boolean",
            "description": "Whether a form refuses to save the customer without a value for it. `false` when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "show_in_registration": {
            "type": "boolean",
            "description": "Whether the website's registration form asks for it. `false` when omitted \u2014 the field is then filled in the admin only.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the field is in use. Switching it off takes it off every form and stops new values being accepted, while the values customers already hold stay readable \u2014 the way to retire a field without losing them. `true` when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "min_length": {
            "type": "integer",
            "format": "int64",
            "description": "The fewest characters a `TEXT` or `TEXTAREA` value may have. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          },
          "max_length": {
            "type": "integer",
            "format": "int64",
            "description": "The most characters a `TEXT` or `TEXTAREA` value may have \u2014 at most 1024 for `TEXT` and 8192 for `TEXTAREA`, which is also the limit when it is omitted. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              120
            ]
          },
          "min_value": {
            "type": "number",
            "format": "double",
            "description": "The smallest value a `NUMBER` field accepts. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              0
            ]
          },
          "max_value": {
            "type": "number",
            "format": "double",
            "description": "The largest value a `NUMBER` field accepts. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              100
            ]
          },
          "group_id": {
            "type": "string",
            "description": "The `customer_attribute_groups` section the admin's customer form shows the field in \u2014 an id of a group of the website. Without one the field is in the default section; deleting its group puts it back there.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Date of birth"
          }
        ]
      },
      "CustomerAttributeUpdate": {
        "type": "object",
        "description": "The `customer_attributes` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The field's label, shown wherever `labels` has none for the locale. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "Date of birth"
            ]
          },
          "labels": {
            "description": "The label in other languages: an object from a locale (`de`, `pt-BR`) to the label in it, each at most 255 characters. A locale it leaves out shows `display_name`. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "de": "Geburtsdatum"
              }
            ]
          },
          "description": {
            "type": "string",
            "description": "The hint shown under the field on a form. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "We send you a gift on your birthday."
            ]
          },
          "options": {
            "description": "The choices of a `SELECT` or `MULTISELECT` field, in the order a form lists them: each `{value, display_name, labels}`, where `value` is what a customer's `attributes` stores and is unique within the field. At least one and at most 100 for those two types, none for the others. Replaced whole when sent.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "value": "store_a",
                  "display_name": "Store A"
                }
              ]
            ]
          },
          "is_required": {
            "type": "boolean",
            "description": "Whether a form refuses to save the customer without a value for it. `false` when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "show_in_registration": {
            "type": "boolean",
            "description": "Whether the website's registration form asks for it. `false` when omitted \u2014 the field is then filled in the admin only.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the field is in use. Switching it off takes it off every form and stops new values being accepted, while the values customers already hold stay readable \u2014 the way to retire a field without losing them. `true` when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "min_length": {
            "type": "integer",
            "format": "int64",
            "description": "The fewest characters a `TEXT` or `TEXTAREA` value may have. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              2
            ]
          },
          "max_length": {
            "type": "integer",
            "format": "int64",
            "description": "The most characters a `TEXT` or `TEXTAREA` value may have \u2014 at most 1024 for `TEXT` and 8192 for `TEXTAREA`, which is also the limit when it is omitted. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              120
            ]
          },
          "min_value": {
            "type": "number",
            "format": "double",
            "description": "The smallest value a `NUMBER` field accepts. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              0
            ]
          },
          "max_value": {
            "type": "number",
            "format": "double",
            "description": "The largest value a `NUMBER` field accepts. Not allowed on other types.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              100
            ]
          },
          "group_id": {
            "type": "string",
            "description": "The `customer_attribute_groups` section the admin's customer form shows the field in \u2014 an id of a group of the website. Without one the field is in the default section; deleting its group puts it back there.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "examples": [
          {
            "display_name": "Date of birth"
          }
        ]
      },
      "CustomerGroup": {
        "type": "object",
        "description": "A group the website's customers are segmented into \u2014 what a page can be shown to or hidden from, and whose version of a page a customer sees. A `MANUAL` group holds the customers assigned to it; a `DYNAMIC` one holds whoever matches its rule. Deleting a group takes it off every customer.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/customer_groups/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The group's name, unique on the website \u2014 how the tenant tells groups apart wherever one is picked. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Wholesale buyers"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the group is for, for the people who manage it. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL"
          },
          "type": {
            "type": "string",
            "description": "How the group gets its members: `MANUAL` \u2014 the customers put in it by hand, `DYNAMIC` \u2014 the customers its `rule` matches. `MANUAL` when omitted; fixed at creation.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "MANUAL"
            ]
          },
          "rule": {
            "type": "string",
            "description": "Who is in a `DYNAMIC` group: a filter over a customer's `email`, `tags` and `create_time`, written like the `filter` of the customers List \u2014 the group holds exactly the customers that List returns for it, and `group_ids` follows a new rule shortly after it is saved. A rule that does not parse or names another field is refused. Without a rule the group has no members. A `MANUAL` group has none. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "tags:\"vip\""
            ]
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "Which group wins when a customer is in several that each have their own version of a page: the higher number. 0 when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              10
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/customer_groups/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Wholesale buyers",
            "description": "string",
            "type": "MANUAL",
            "rule": "tags:\"vip\"",
            "priority": 10
          }
        ]
      },
      "CustomerGroupCreate": {
        "type": "object",
        "description": "The `customer_groups` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The group's name, unique on the website \u2014 how the tenant tells groups apart wherever one is picked. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Wholesale buyers"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the group is for, for the people who manage it. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL"
          },
          "type": {
            "type": "string",
            "description": "How the group gets its members: `MANUAL` \u2014 the customers put in it by hand, `DYNAMIC` \u2014 the customers its `rule` matches. `MANUAL` when omitted; fixed at creation.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "MANUAL"
            ]
          },
          "rule": {
            "type": "string",
            "description": "Who is in a `DYNAMIC` group: a filter over a customer's `email`, `tags` and `create_time`, written like the `filter` of the customers List \u2014 the group holds exactly the customers that List returns for it, and `group_ids` follows a new rule shortly after it is saved. A rule that does not parse or names another field is refused. Without a rule the group has no members. A `MANUAL` group has none. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "tags:\"vip\""
            ]
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "Which group wins when a customer is in several that each have their own version of a page: the higher number. 0 when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              10
            ]
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Wholesale buyers"
          }
        ]
      },
      "CustomerGroupUpdate": {
        "type": "object",
        "description": "The `customer_groups` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The group's name, unique on the website \u2014 how the tenant tells groups apart wherever one is picked. Not blank, at most 255 characters.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Wholesale buyers"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the group is for, for the people who manage it. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL"
          },
          "rule": {
            "type": "string",
            "description": "Who is in a `DYNAMIC` group: a filter over a customer's `email`, `tags` and `create_time`, written like the `filter` of the customers List \u2014 the group holds exactly the customers that List returns for it, and `group_ids` follows a new rule shortly after it is saved. A rule that does not parse or names another field is refused. Without a rule the group has no members. A `MANUAL` group has none. At most 2000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "tags:\"vip\""
            ]
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "Which group wins when a customer is in several that each have their own version of a page: the higher number. 0 when omitted.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              10
            ]
          }
        },
        "examples": [
          {
            "display_name": "Wholesale buyers"
          }
        ]
      },
      "Customer": {
        "type": "object",
        "description": "A visitor who has an account on the website \u2014 registered on the site itself or added here by the tenant. A customer belongs to one website: the same address on another website is another customer. Groups are assigned by hand in `manual_group_ids`; `group_ids` is the resulting membership. The fields the website adds to its customers are filled in `attributes`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/customers/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "email": {
            "type": "string",
            "description": "The address the customer signs in to the website with. Unique on the website, compared and stored lowercase with surrounding spaces dropped. Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "ada@example.com"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The name the customer is greeted by on the website and listed under in the admin. At most 255 characters.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "Ada Lovelace"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Free-form labels to segment customers by, each 1 to 64 characters; a repeated one is kept once. `filter=tags:\"vip\"` lists the customers carrying a tag.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              [
                "vip"
              ]
            ]
          },
          "manual_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The groups this customer was put in by hand \u2014 ids of `customer_groups` of the website whose `type` is `MANUAL`. A deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every group the customer is in: the ones in `manual_group_ids` and the `DYNAMIC` ones whose rule they match, derived again whenever the customer is written and whenever such a rule changes. This is the membership the website decides by, and it is maintained by the server.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the customer may sign in. A new customer is active; switching it off keeps the account but stops its sessions from being renewed.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "attributes": {
            "description": "The customer's values of the fields the website defines in `customer_attributes`: an object from a field's `key` to its value \u2014 a string for `TEXT`, `TEXTAREA`, `SELECT` and `DATE` (`YYYY-MM-DD`), a number for `NUMBER`, `true` or `false` for `BOOLEAN`, an array of option values for `MULTISELECT`. Replaced whole when sent: a field it leaves out, or sends as `null`, an empty string or an empty array, has no value, and a field with `is_required` must have one \u2014 on create too, where an absent object counts as an empty one. A key the website has no field for, or a value its field does not accept, is refused on `attributes.<key>`. The value of a field switched off with `is_active` is kept as it is: sent back unchanged it is accepted, changed it is refused. Deleting a field removes its value from every customer. Omitted when empty.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "birth_date": "1990-04-12",
                "preferred_store": "north"
              }
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/customers/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "email": "ada@example.com",
            "display_name": "Ada Lovelace",
            "tags": [
              "vip"
            ],
            "manual_group_ids": [],
            "group_ids": [],
            "is_active": true,
            "attributes": {
              "birth_date": "1990-04-12",
              "preferred_store": "north"
            }
          }
        ]
      },
      "CustomerCreate": {
        "type": "object",
        "description": "The `customers` fields a client may set on create.",
        "properties": {
          "email": {
            "type": "string",
            "description": "The address the customer signs in to the website with. Unique on the website, compared and stored lowercase with surrounding spaces dropped. Required on create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "ada@example.com"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The name the customer is greeted by on the website and listed under in the admin. At most 255 characters.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "Ada Lovelace"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Free-form labels to segment customers by, each 1 to 64 characters; a repeated one is kept once. `filter=tags:\"vip\"` lists the customers carrying a tag.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              [
                "vip"
              ]
            ]
          },
          "manual_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The groups this customer was put in by hand \u2014 ids of `customer_groups` of the website whose `type` is `MANUAL`. A deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the customer may sign in. A new customer is active; switching it off keeps the account but stops its sessions from being renewed.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "attributes": {
            "description": "The customer's values of the fields the website defines in `customer_attributes`: an object from a field's `key` to its value \u2014 a string for `TEXT`, `TEXTAREA`, `SELECT` and `DATE` (`YYYY-MM-DD`), a number for `NUMBER`, `true` or `false` for `BOOLEAN`, an array of option values for `MULTISELECT`. Replaced whole when sent: a field it leaves out, or sends as `null`, an empty string or an empty array, has no value, and a field with `is_required` must have one \u2014 on create too, where an absent object counts as an empty one. A key the website has no field for, or a value its field does not accept, is refused on `attributes.<key>`. The value of a field switched off with `is_active` is kept as it is: sent back unchanged it is accepted, changed it is refused. Deleting a field removes its value from every customer. Omitted when empty.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "birth_date": "1990-04-12",
                "preferred_store": "north"
              }
            ]
          },
          "password": {
            "type": "string",
            "description": "The customer's password: at least 8 characters with a letter and a digit. Required on create; on update it sets a new one and signs the customer out of every session. Write-only \u2014 never returned.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY"
          }
        },
        "examples": [
          {
            "email": "ada@example.com",
            "display_name": "Ada Lovelace"
          }
        ]
      },
      "CustomerUpdate": {
        "type": "object",
        "description": "The `customers` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The name the customer is greeted by on the website and listed under in the admin. At most 255 characters.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "Ada Lovelace"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Free-form labels to segment customers by, each 1 to 64 characters; a repeated one is kept once. `filter=tags:\"vip\"` lists the customers carrying a tag.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              [
                "vip"
              ]
            ]
          },
          "manual_group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The groups this customer was put in by hand \u2014 ids of `customer_groups` of the website whose `type` is `MANUAL`. A deleted group drops out of it on its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the customer may sign in. A new customer is active; switching it off keeps the account but stops its sessions from being renewed.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "attributes": {
            "description": "The customer's values of the fields the website defines in `customer_attributes`: an object from a field's `key` to its value \u2014 a string for `TEXT`, `TEXTAREA`, `SELECT` and `DATE` (`YYYY-MM-DD`), a number for `NUMBER`, `true` or `false` for `BOOLEAN`, an array of option values for `MULTISELECT`. Replaced whole when sent: a field it leaves out, or sends as `null`, an empty string or an empty array, has no value, and a field with `is_required` must have one \u2014 on create too, where an absent object counts as an empty one. A key the website has no field for, or a value its field does not accept, is refused on `attributes.<key>`. The value of a field switched off with `is_active` is kept as it is: sent back unchanged it is accepted, changed it is refused. Deleting a field removes its value from every customer. Omitted when empty.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              {
                "birth_date": "1990-04-12",
                "preferred_store": "north"
              }
            ]
          },
          "password": {
            "type": "string",
            "description": "The customer's password: at least 8 characters with a letter and a digit. Required on create; on update it sets a new one and signs the customer out of every session. Write-only \u2014 never returned.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY"
          }
        },
        "examples": [
          {
            "display_name": "Ada Lovelace",
            "tags": [
              "vip"
            ]
          }
        ]
      },
      "Dashboard": {
        "type": "object",
        "description": "The widget grid of one website's dashboard: which tiles are on it, where each one sits in a 12-column grid, and how each is configured. There is exactly one per website and it always exists \u2014 read it before anything was ever saved and you get the platform's default layout rather than a 404, and `:reset` puts that layout back. What a tile can be is `dashboard_widget_types`; what the analytics tiles draw is `analytics_metrics`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/dashboard"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "widgets": {
            "description": "The tiles on this dashboard, as a list of `{widget_id, type, x, y, width, height, settings}`. `widget_id` is yours to choose and must be unique here; `type` is a `dashboard_widget_types` id; the geometry is in a 12-column grid whose rows go on for as long as you need. Sent whole: an Update replaces the layout rather than merging tile by tile.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "widget_id": "kpi_page_views",
                  "type": "kpi_page_views",
                  "x": 0,
                  "y": 0,
                  "width": 3,
                  "height": 2,
                  "settings": {
                    "period": "LAST_7_DAYS"
                  }
                }
              ]
            ]
          },
          "layout_version": {
            "type": "integer",
            "format": "int64",
            "description": "The shape the stored layout is in. The platform raises it when it migrates a dashboard saved by an older release; a client reads it and never sends it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1
            ]
          },
          "is_default": {
            "type": "boolean",
            "description": "True while nobody has ever saved a dashboard for this website and what you are reading is the platform's default layout. It comes with no `etag` and no timestamps, because there is nothing to be a version of yet \u2014 so the first Update sends no `If-Match` and every later one does.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              true
            ]
          }
        },
        "required": [
          "name"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/dashboard",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "widgets": [
              {
                "widget_id": "kpi_page_views",
                "type": "kpi_page_views",
                "x": 0,
                "y": 0,
                "width": 3,
                "height": 2,
                "settings": {
                  "period": "LAST_7_DAYS"
                }
              }
            ],
            "layout_version": 1,
            "is_default": true
          }
        ]
      },
      "DashboardCreate": {
        "type": "object",
        "description": "The `dashboard` fields a client may set on create.",
        "properties": {
          "widgets": {
            "description": "The tiles on this dashboard, as a list of `{widget_id, type, x, y, width, height, settings}`. `widget_id` is yours to choose and must be unique here; `type` is a `dashboard_widget_types` id; the geometry is in a 12-column grid whose rows go on for as long as you need. Sent whole: an Update replaces the layout rather than merging tile by tile.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "widget_id": "kpi_page_views",
                  "type": "kpi_page_views",
                  "x": 0,
                  "y": 0,
                  "width": 3,
                  "height": 2,
                  "settings": {
                    "period": "LAST_7_DAYS"
                  }
                }
              ]
            ]
          }
        },
        "examples": [
          {
            "widgets": [
              {
                "widget_id": "kpi_page_views",
                "type": "kpi_page_views",
                "x": 0,
                "y": 0,
                "width": 3,
                "height": 2,
                "settings": {
                  "period": "LAST_7_DAYS"
                }
              }
            ]
          }
        ]
      },
      "DashboardUpdate": {
        "type": "object",
        "description": "The `dashboard` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "widgets": {
            "description": "The tiles on this dashboard, as a list of `{widget_id, type, x, y, width, height, settings}`. `widget_id` is yours to choose and must be unique here; `type` is a `dashboard_widget_types` id; the geometry is in a 12-column grid whose rows go on for as long as you need. Sent whole: an Update replaces the layout rather than merging tile by tile.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                {
                  "widget_id": "kpi_page_views",
                  "type": "kpi_page_views",
                  "x": 0,
                  "y": 0,
                  "width": 3,
                  "height": 2,
                  "settings": {
                    "period": "LAST_7_DAYS"
                  }
                }
              ]
            ]
          }
        },
        "examples": [
          {
            "widgets": [
              {
                "widget_id": "kpi_page_views",
                "type": "kpi_page_views",
                "x": 0,
                "y": 0,
                "width": 3,
                "height": 2,
                "settings": {
                  "period": "LAST_7_DAYS"
                }
              }
            ]
          }
        ]
      },
      "DashboardWidgetType": {
        "type": "object",
        "description": "Every tile a dashboard can hold, with what it shows, how big it may be and what it can be configured with. Nothing here is stored or writable: it is the platform's catalogue, and a type your client does not recognise is one it should draw as a placeholder rather than drop \u2014 that is what lets the platform ship a new tile before your client knows about it. A saved dashboard is validated against this same list.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "dashboard_widget_types/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The tile's name as a person reads it, for the \u00abadd widget\u00bb drawer and the tile's own header.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "Unique visitors"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the tile shows and \u2014 where it matters \u2014 what its number leaves out, in a sentence or two the drawer and the tile can show as help text.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "category": {
            "type": "string",
            "description": "Which section of the \u00abadd widget\u00bb drawer this tile belongs to: `ANALYTICS`, `CONTENT` or `PLATFORM`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "ANALYTICS"
            ]
          },
          "visualization": {
            "type": "string",
            "description": "How the tile is drawn: `KPI` (one number with its trend), `LINE_CHART`, `BAR_CHART`, or `CUSTOM` \u2014 which means the admin has a renderer of its own for this id.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "KPI"
            ]
          },
          "metric_id": {
            "type": "string",
            "description": "For an analytics tile, the `analytics_metrics` id it draws \u2014 the row whose `:query` answers its number. Absent on every other tile.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "unique_visitors"
            ]
          },
          "default_size": {
            "description": "`{width, height}` in grid cells \u2014 the size the tile is added at when somebody picks it out of the drawer.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              {
                "width": 3,
                "height": 2
              }
            ]
          },
          "min_size": {
            "description": "The smallest `{width, height}` this tile still reads at. A saved layout below it is INVALID_ARGUMENT, and a resize handle stops here.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              {
                "width": 2,
                "height": 2
              }
            ]
          },
          "max_size": {
            "description": "The largest `{width, height}` this tile is worth. It is a range together with `min_size`, not a list of allowed sizes \u2014 a tile that has exactly one size says so by making the two equal.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              {
                "width": 6,
                "height": 4
              }
            ]
          },
          "singleton_per_dashboard": {
            "type": "boolean",
            "description": "True for a tile that makes sense at most once on a page \u2014 a checklist, a summary of the whole site. A second one is refused on Update rather than drawn twice.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              false
            ]
          },
          "setting_descriptors": {
            "description": "What this tile can be configured with: `{key, display_name, type, default, allowed_values}` per setting. It is what the widget's settings drawer is built from and what a saved `widget.settings` is validated against \u2014 a key that is not here, or a value outside `allowed_values`, is refused.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              [
                {
                  "key": "period",
                  "display_name": "Period",
                  "type": "ENUM",
                  "default": "INHERIT",
                  "allowed_values": [
                    "INHERIT",
                    "TODAY",
                    "LAST_7_DAYS",
                    "LAST_30_DAYS"
                  ]
                }
              ]
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "dashboard_widget_types/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Unique visitors",
            "description": "string",
            "category": "ANALYTICS",
            "visualization": "KPI",
            "metric_id": "unique_visitors",
            "default_size": {
              "width": 3,
              "height": 2
            },
            "min_size": {
              "width": 2,
              "height": 2
            },
            "max_size": {
              "width": 6,
              "height": 4
            },
            "singleton_per_dashboard": false,
            "setting_descriptors": [
              {
                "key": "period",
                "display_name": "Period",
                "type": "ENUM",
                "default": "INHERIT",
                "allowed_values": [
                  "INHERIT",
                  "TODAY",
                  "LAST_7_DAYS",
                  "LAST_30_DAYS"
                ]
              }
            ]
          }
        ]
      },
      "DashboardWidgetTypeCreate": {
        "type": "object",
        "description": "The `dashboard_widget_types` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "DashboardWidgetTypeUpdate": {
        "type": "object",
        "description": "The `dashboard_widget_types` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "EditorialAiPolicy": {
        "type": "object",
        "description": "How this website's editorial desk produces content when its plan, or a slot, says `AI_GENERATED`: which of the account's AI agents write, review, translate, propose topics and draw the cover, what the site is about and in what voice, how long an article should be, what it must not say, which views take a translation, and whether an article that passed review may go live on its own. One per website, and it always exists \u2014 a website that never configured one reads back the defaults, and the first Update stores it. Every agent named here is checked against its role's contract on the write.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/editorial_ai_policy"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "writer_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry of this website's account that writes the article \u2014 a copy of the platform's `mooverapp-article-writer`. Without it the `AI_GENERATED` mode is not ready. Its output contract is checked on every write and again when a run starts.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "reviewer_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that scores the finished article \u2014 a copy of `mooverapp-article-reviewer`. Without a reviewer no run reaches `PASSED`, and `auto_publish` cannot be switched on.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f608"
            ]
          },
          "translator_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that translates the article into the website's other languages \u2014 a copy of `mooverapp-article-translator`. Absent, no translation is made and `require_translations` is not checked.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f609"
            ]
          },
          "topic_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that proposes topics for the backlog \u2014 a copy of `mooverapp-topic-strategist`. Needed for a `TOPICS` run and for the automatic refill `topic_backlog_min` switches on.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60a"
            ]
          },
          "image_prompt_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that turns the article into a brief for the image model \u2014 a copy of the platform's `mooverapp-image-prompt-generator`. Set together with `image_agent_id`, or neither.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60b"
            ]
          },
          "image_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that draws the cover \u2014 a copy of `mooverapp-featured-image`, an `IMAGE` agent on an image model. Set together with `image_prompt_agent_id`, or neither.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60c"
            ]
          },
          "site_brief": {
            "type": "string",
            "description": "What the website is about, in a paragraph the writer and the topic strategist read before every article. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "A field guide to whales, written for curious readers."
            ]
          },
          "voice": {
            "type": "string",
            "description": "The tone the articles are written in \u2014 calm and practical, playful, formal. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "warm, precise, never breathless"
            ]
          },
          "audience": {
            "type": "string",
            "description": "Who the articles are for, so the writer pitches vocabulary and depth accordingly. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "families planning a whale-watching trip"
            ]
          },
          "article_word_count": {
            "type": "integer",
            "format": "int64",
            "description": "How long an article should be, in words of its body. Between 300 and 3000; defaults to 1000. An article far outside the target is flagged by the checks.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              1000
            ]
          },
          "banned_phrases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phrases an article must not contain \u2014 a case-insensitive occurrence of any of them is a BLOCKER in the verdict. At most 100, none blank, each at most 200 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "delve",
                "in today's fast-paced world"
              ]
            ]
          },
          "review_min_score": {
            "type": "integer",
            "format": "int64",
            "description": "The reviewer's score, from 0 to 100, an article needs to pass. Defaults to 80. Below it the verdict is `NEEDS_REVIEW` and a person decides.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              80
            ]
          },
          "max_generations_per_day": {
            "type": "integer",
            "format": "int64",
            "description": "How many runs the desk may start by itself per UTC day, between 1 and 1000; defaults to 20. Runs a person starts do not count. A fuse against a loop, not a budget \u2014 the AI balance is the account's.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              20
            ]
          },
          "auto_publish": {
            "type": "boolean",
            "description": "Whether an article whose verdict is `PASSED`, and which nobody has edited, goes live on its slot's date with no person involved. Off by default; requires a reviewer. Read at the date, so switching it off takes effect at once.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              false
            ]
          },
          "translate_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which of this website's views take a translation. Empty \u2014 every active view whose locale differs from the site's language. A view in the site's language, or switched off, is never a target. Two views on one locale get one translation and two overlays.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "64ff1f77aa01b2c3d4e5f60d"
              ]
            ]
          },
          "require_translations": {
            "type": "boolean",
            "description": "Whether `PASSED` waits for every translation. On by default: a translation that failed or came back in another shape makes the verdict `NEEDS_REVIEW`. Off, it is listed as a MINOR issue and the article may still go out. Not checked without a translator.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              true
            ]
          },
          "topic_backlog_min": {
            "type": "integer",
            "format": "int64",
            "description": "The backlog floor that starts a `TOPICS` run by itself: when `CANDIDATE` plus `PROPOSED` topics fall below it, the desk asks the strategist for a batch \u2014 at most once a day, and counted against `max_generations_per_day`. Between 0 and 100; 0 (the default) switches the refill off. Needs `topic_agent_id`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              5
            ]
          },
          "topic_batch_size": {
            "type": "integer",
            "format": "int64",
            "description": "How many topics one `TOPICS` run asks for, between 1 and 30; defaults to 10. A run's own `topic_count` overrides it.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              10
            ]
          },
          "topic_approval": {
            "type": "string",
            "description": "What a proposed topic becomes: `REQUIRED` (the default) \u2014 `PROPOSED`, waiting for `:accept` before the planner may schedule it; `AUTO` \u2014 `CANDIDATE` at once, in the backlog like a topic a person wrote.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "REQUIRED"
            ]
          },
          "image_style": {
            "type": "string",
            "description": "The site's visual style, appended to every image brief \u2014 a photographic style, a palette, a mood. At most 2,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "documentary photography, natural light, muted blues"
            ]
          },
          "require_image": {
            "type": "boolean",
            "description": "Whether `PASSED` waits for the cover. Off by default: an article whose cover failed is listed with a MINOR issue and may still go out. On, it is `NEEDS_REVIEW`. Needs the two image agents.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              false
            ]
          }
        },
        "required": [
          "name"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/editorial_ai_policy",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "writer_agent_id": "64ff1f77aa01b2c3d4e5f607",
            "reviewer_agent_id": "64ff1f77aa01b2c3d4e5f608",
            "translator_agent_id": "64ff1f77aa01b2c3d4e5f609",
            "topic_agent_id": "64ff1f77aa01b2c3d4e5f60a",
            "image_prompt_agent_id": "64ff1f77aa01b2c3d4e5f60b",
            "image_agent_id": "64ff1f77aa01b2c3d4e5f60c",
            "site_brief": "A field guide to whales, written for curious readers.",
            "voice": "warm, precise, never breathless",
            "audience": "families planning a whale-watching trip",
            "article_word_count": 1000,
            "banned_phrases": [
              "delve",
              "in today's fast-paced world"
            ],
            "review_min_score": 80,
            "max_generations_per_day": 20,
            "auto_publish": false,
            "translate_view_ids": [
              "64ff1f77aa01b2c3d4e5f60d"
            ],
            "require_translations": true,
            "topic_backlog_min": 5,
            "topic_batch_size": 10,
            "topic_approval": "REQUIRED",
            "image_style": "documentary photography, natural light, muted blues",
            "require_image": false
          }
        ]
      },
      "EditorialAiPolicyCreate": {
        "type": "object",
        "description": "The `editorial_ai_policy` fields a client may set on create.",
        "properties": {
          "writer_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry of this website's account that writes the article \u2014 a copy of the platform's `mooverapp-article-writer`. Without it the `AI_GENERATED` mode is not ready. Its output contract is checked on every write and again when a run starts.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "reviewer_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that scores the finished article \u2014 a copy of `mooverapp-article-reviewer`. Without a reviewer no run reaches `PASSED`, and `auto_publish` cannot be switched on.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f608"
            ]
          },
          "translator_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that translates the article into the website's other languages \u2014 a copy of `mooverapp-article-translator`. Absent, no translation is made and `require_translations` is not checked.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f609"
            ]
          },
          "topic_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that proposes topics for the backlog \u2014 a copy of `mooverapp-topic-strategist`. Needed for a `TOPICS` run and for the automatic refill `topic_backlog_min` switches on.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60a"
            ]
          },
          "image_prompt_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that turns the article into a brief for the image model \u2014 a copy of the platform's `mooverapp-image-prompt-generator`. Set together with `image_agent_id`, or neither.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60b"
            ]
          },
          "image_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that draws the cover \u2014 a copy of `mooverapp-featured-image`, an `IMAGE` agent on an image model. Set together with `image_prompt_agent_id`, or neither.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60c"
            ]
          },
          "site_brief": {
            "type": "string",
            "description": "What the website is about, in a paragraph the writer and the topic strategist read before every article. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "A field guide to whales, written for curious readers."
            ]
          },
          "voice": {
            "type": "string",
            "description": "The tone the articles are written in \u2014 calm and practical, playful, formal. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "warm, precise, never breathless"
            ]
          },
          "audience": {
            "type": "string",
            "description": "Who the articles are for, so the writer pitches vocabulary and depth accordingly. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "families planning a whale-watching trip"
            ]
          },
          "article_word_count": {
            "type": "integer",
            "format": "int64",
            "description": "How long an article should be, in words of its body. Between 300 and 3000; defaults to 1000. An article far outside the target is flagged by the checks.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              1000
            ]
          },
          "banned_phrases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phrases an article must not contain \u2014 a case-insensitive occurrence of any of them is a BLOCKER in the verdict. At most 100, none blank, each at most 200 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "delve",
                "in today's fast-paced world"
              ]
            ]
          },
          "review_min_score": {
            "type": "integer",
            "format": "int64",
            "description": "The reviewer's score, from 0 to 100, an article needs to pass. Defaults to 80. Below it the verdict is `NEEDS_REVIEW` and a person decides.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              80
            ]
          },
          "max_generations_per_day": {
            "type": "integer",
            "format": "int64",
            "description": "How many runs the desk may start by itself per UTC day, between 1 and 1000; defaults to 20. Runs a person starts do not count. A fuse against a loop, not a budget \u2014 the AI balance is the account's.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              20
            ]
          },
          "auto_publish": {
            "type": "boolean",
            "description": "Whether an article whose verdict is `PASSED`, and which nobody has edited, goes live on its slot's date with no person involved. Off by default; requires a reviewer. Read at the date, so switching it off takes effect at once.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              false
            ]
          },
          "translate_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which of this website's views take a translation. Empty \u2014 every active view whose locale differs from the site's language. A view in the site's language, or switched off, is never a target. Two views on one locale get one translation and two overlays.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "64ff1f77aa01b2c3d4e5f60d"
              ]
            ]
          },
          "require_translations": {
            "type": "boolean",
            "description": "Whether `PASSED` waits for every translation. On by default: a translation that failed or came back in another shape makes the verdict `NEEDS_REVIEW`. Off, it is listed as a MINOR issue and the article may still go out. Not checked without a translator.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              true
            ]
          },
          "topic_backlog_min": {
            "type": "integer",
            "format": "int64",
            "description": "The backlog floor that starts a `TOPICS` run by itself: when `CANDIDATE` plus `PROPOSED` topics fall below it, the desk asks the strategist for a batch \u2014 at most once a day, and counted against `max_generations_per_day`. Between 0 and 100; 0 (the default) switches the refill off. Needs `topic_agent_id`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              5
            ]
          },
          "topic_batch_size": {
            "type": "integer",
            "format": "int64",
            "description": "How many topics one `TOPICS` run asks for, between 1 and 30; defaults to 10. A run's own `topic_count` overrides it.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              10
            ]
          },
          "topic_approval": {
            "type": "string",
            "description": "What a proposed topic becomes: `REQUIRED` (the default) \u2014 `PROPOSED`, waiting for `:accept` before the planner may schedule it; `AUTO` \u2014 `CANDIDATE` at once, in the backlog like a topic a person wrote.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "REQUIRED"
            ]
          },
          "image_style": {
            "type": "string",
            "description": "The site's visual style, appended to every image brief \u2014 a photographic style, a palette, a mood. At most 2,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "documentary photography, natural light, muted blues"
            ]
          },
          "require_image": {
            "type": "boolean",
            "description": "Whether `PASSED` waits for the cover. Off by default: an article whose cover failed is listed with a MINOR issue and may still go out. On, it is `NEEDS_REVIEW`. Needs the two image agents.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              false
            ]
          }
        },
        "examples": [
          {
            "writer_agent_id": "64ff1f77aa01b2c3d4e5f607",
            "reviewer_agent_id": "64ff1f77aa01b2c3d4e5f608"
          }
        ]
      },
      "EditorialAiPolicyUpdate": {
        "type": "object",
        "description": "The `editorial_ai_policy` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "writer_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry of this website's account that writes the article \u2014 a copy of the platform's `mooverapp-article-writer`. Without it the `AI_GENERATED` mode is not ready. Its output contract is checked on every write and again when a run starts.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "reviewer_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that scores the finished article \u2014 a copy of `mooverapp-article-reviewer`. Without a reviewer no run reaches `PASSED`, and `auto_publish` cannot be switched on.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f608"
            ]
          },
          "translator_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that translates the article into the website's other languages \u2014 a copy of `mooverapp-article-translator`. Absent, no translation is made and `require_translations` is not checked.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f609"
            ]
          },
          "topic_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that proposes topics for the backlog \u2014 a copy of `mooverapp-topic-strategist`. Needed for a `TOPICS` run and for the automatic refill `topic_backlog_min` switches on.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60a"
            ]
          },
          "image_prompt_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that turns the article into a brief for the image model \u2014 a copy of the platform's `mooverapp-image-prompt-generator`. Set together with `image_agent_id`, or neither.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60b"
            ]
          },
          "image_agent_id": {
            "type": "string",
            "description": "The `ai_agents` entry that draws the cover \u2014 a copy of `mooverapp-featured-image`, an `IMAGE` agent on an image model. Set together with `image_prompt_agent_id`, or neither.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "64ff1f77aa01b2c3d4e5f60c"
            ]
          },
          "site_brief": {
            "type": "string",
            "description": "What the website is about, in a paragraph the writer and the topic strategist read before every article. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "A field guide to whales, written for curious readers."
            ]
          },
          "voice": {
            "type": "string",
            "description": "The tone the articles are written in \u2014 calm and practical, playful, formal. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "warm, precise, never breathless"
            ]
          },
          "audience": {
            "type": "string",
            "description": "Who the articles are for, so the writer pitches vocabulary and depth accordingly. At most 4,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "families planning a whale-watching trip"
            ]
          },
          "article_word_count": {
            "type": "integer",
            "format": "int64",
            "description": "How long an article should be, in words of its body. Between 300 and 3000; defaults to 1000. An article far outside the target is flagged by the checks.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              1000
            ]
          },
          "banned_phrases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Phrases an article must not contain \u2014 a case-insensitive occurrence of any of them is a BLOCKER in the verdict. At most 100, none blank, each at most 200 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "delve",
                "in today's fast-paced world"
              ]
            ]
          },
          "review_min_score": {
            "type": "integer",
            "format": "int64",
            "description": "The reviewer's score, from 0 to 100, an article needs to pass. Defaults to 80. Below it the verdict is `NEEDS_REVIEW` and a person decides.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              80
            ]
          },
          "max_generations_per_day": {
            "type": "integer",
            "format": "int64",
            "description": "How many runs the desk may start by itself per UTC day, between 1 and 1000; defaults to 20. Runs a person starts do not count. A fuse against a loop, not a budget \u2014 the AI balance is the account's.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              20
            ]
          },
          "auto_publish": {
            "type": "boolean",
            "description": "Whether an article whose verdict is `PASSED`, and which nobody has edited, goes live on its slot's date with no person involved. Off by default; requires a reviewer. Read at the date, so switching it off takes effect at once.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              false
            ]
          },
          "translate_view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which of this website's views take a translation. Empty \u2014 every active view whose locale differs from the site's language. A view in the site's language, or switched off, is never a target. Two views on one locale get one translation and two overlays.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "64ff1f77aa01b2c3d4e5f60d"
              ]
            ]
          },
          "require_translations": {
            "type": "boolean",
            "description": "Whether `PASSED` waits for every translation. On by default: a translation that failed or came back in another shape makes the verdict `NEEDS_REVIEW`. Off, it is listed as a MINOR issue and the article may still go out. Not checked without a translator.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              true
            ]
          },
          "topic_backlog_min": {
            "type": "integer",
            "format": "int64",
            "description": "The backlog floor that starts a `TOPICS` run by itself: when `CANDIDATE` plus `PROPOSED` topics fall below it, the desk asks the strategist for a batch \u2014 at most once a day, and counted against `max_generations_per_day`. Between 0 and 100; 0 (the default) switches the refill off. Needs `topic_agent_id`.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              5
            ]
          },
          "topic_batch_size": {
            "type": "integer",
            "format": "int64",
            "description": "How many topics one `TOPICS` run asks for, between 1 and 30; defaults to 10. A run's own `topic_count` overrides it.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              10
            ]
          },
          "topic_approval": {
            "type": "string",
            "description": "What a proposed topic becomes: `REQUIRED` (the default) \u2014 `PROPOSED`, waiting for `:accept` before the planner may schedule it; `AUTO` \u2014 `CANDIDATE` at once, in the backlog like a topic a person wrote.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "REQUIRED"
            ]
          },
          "image_style": {
            "type": "string",
            "description": "The site's visual style, appended to every image brief \u2014 a photographic style, a palette, a mood. At most 2,000 characters.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "documentary photography, natural light, muted blues"
            ]
          },
          "require_image": {
            "type": "boolean",
            "description": "Whether `PASSED` waits for the cover. Off by default: an article whose cover failed is listed with a MINOR issue and may still go out. On, it is `NEEDS_REVIEW`. Needs the two image agents.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              false
            ]
          }
        },
        "examples": [
          {
            "writer_agent_id": "64ff1f77aa01b2c3d4e5f607",
            "reviewer_agent_id": "64ff1f77aa01b2c3d4e5f608"
          }
        ]
      },
      "EditorialGeneration": {
        "type": "object",
        "description": "One run of the desk's pipeline. For an article: the text the writer produced, the checks and the review it went through, the translations and the cover that followed, where it was applied, and what it cost. For topics: the batch the strategist proposed and what of it was new. Runs are started by the desk \u2014 when a slot comes within its writing time, or the backlog falls under its floor \u2014 or by a person with Create; they run in the background, so read the run until `state` is final. There is no Update and no Delete: history is not edited, and a new run on a drafted slot is how an article is regenerated \u2014 by parts, and never over a field a person edited. `:cancel` stops a live run, `:retry` resumes a failed one at the step that failed.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/editorial_generations/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "kind": {
            "type": "string",
            "description": "What the run produces: `ARTICLE` \u2014 one slot's post, with its translations and cover where the policy names the agents; `TOPICS` \u2014 a batch of proposed topics for the backlog. Fixed after create.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "ARTICLE"
            ]
          },
          "slot_id": {
            "type": "string",
            "description": "The `editorial_slots` entry the run writes for. Required for an `ARTICLE` run and refused for a `TOPICS` run; the slot's content mode must be `AI_GENERATED`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "parts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which parts an `ARTICLE` run produces: `TEXT`, `TRANSLATIONS`, `IMAGE`. Empty \u2014 every part the policy enables, and the translations and the cover only for an article whose text verdict is `PASSED`. Named explicitly, the parts are produced whatever the verdict. On a drafted slot this is regeneration: the fields a person edited are kept and named on the step, and `TEXT` may be left out once a run has written the slot's article. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              [
                "TEXT",
                "TRANSLATIONS"
              ]
            ]
          },
          "view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views a `TRANSLATIONS` part covers, each one a view the policy would translate into; empty \u2014 all of them. Fixed after create.",
            "x-field-behavior": "IMMUTABLE"
          },
          "topic_count": {
            "type": "integer",
            "format": "int64",
            "description": "How many topics a `TOPICS` run asks for, between 1 and 30; defaults to the policy's `topic_batch_size`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              10
            ]
          },
          "image_model_id": {
            "type": "string",
            "description": "The `ai_models` entry the cover is drawn on for this run, in place of the image agent's `preferred_model_id`. Only on an `ARTICLE` run that draws the cover \u2014 `parts` naming `IMAGE`, or empty on a policy with both image agents; the model must be one the image agent can run on, and is refused with the reason otherwise. Kept by `:retry`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              "flux-2-max"
            ]
          },
          "image_notes": {
            "type": "string",
            "description": "A person's instructions for the cover of this run, at most 2000 characters. The image brief writer receives them as its `notes` variable, where its instruction declares one, and the image agent receives them appended to its prompt as they are. Only on a run that draws the cover, like `image_model_id`. Kept by `:retry`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              "The seabirds are above the water; the whale is below the surface."
            ]
          },
          "trigger": {
            "type": "string",
            "description": "Who started the run: `SCHEDULE` \u2014 the desk, when the slot came within its writing time or the backlog fell under its floor; `MANUAL` \u2014 a person, through Create. Only `SCHEDULE` runs count against the policy's daily limit.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "SCHEDULE"
            ]
          },
          "pipeline_version": {
            "type": "string",
            "description": "Which sequence of steps the run follows, fixed when it was created: `article-v1` for an article, `topics-v1` for topics. A run of a version the platform no longer knows ends `FAILED`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "article-v1"
            ]
          },
          "state": {
            "type": "string",
            "description": "`QUEUED`, `RUNNING`, then `SUCCEEDED`, `FAILED` or `CANCELLED`. The verdict is a separate question: a `SUCCEEDED` run may say the article needs a person.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "SUCCEEDED"
            ]
          },
          "steps": {
            "description": "Every step of the pipeline with its state \u2014 `PENDING`, `RUNNING`, `WAITING`, `SUCCEEDED`, `FAILED`, `SKIPPED`, `CANCELLED` \u2014 the `ai_executions` entry behind an agent step, the `locale` and `view_ids` of a translation step, why a waiting step waits and until when, its automatic retries, its error, and the `skipped_fields` a step left to the person who had edited them.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "verdict": {
            "description": "What the run's checks, its reviewer and its parts made of the article: `result` (`PASSED` or `NEEDS_REVIEW`), the reviewer's `score`, and every `issue` with its `code`, `severity`, `message`, the `step` it came from and, for a translation, its `locale`. Present once the checks ran; final when the run is.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "article": {
            "description": "The article as the writer produced it and the desk rendered it \u2014 the structured document the post's HTML was printed from and the translator received. The run's revision of the text, kept whatever happens to the post.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "result": {
            "description": "Where the run was applied. An `ARTICLE` run: the `target_id` of the post it wrote, the `view_ids` it localised, and the `media_id` of the cover it put in the media library. A `TOPICS` run: `created_topic_ids` and `duplicates_skipped`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "cost": {
            "description": "What the run's executions were charged to the AI balance, summed, as Money. Absent while none was charged \u2014 a run entirely on the account's own key.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "policy_snapshot": {
            "description": "The editorial AI policy as it was when the run was created. Editing the policy does not change a run in flight; `auto_publish` alone is read at the date.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "error": {
            "description": "Why a `FAILED` run stopped, in the same shape as an API error: `code`, `status`, `message` and a `PRECONDITION_FAILURE` whose `type` names the reason.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "end_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the run reached a final state (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/editorial_generations/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "kind": "ARTICLE",
            "slot_id": "64ff1f77aa01b2c3d4e5f607",
            "parts": [
              "TEXT",
              "TRANSLATIONS"
            ],
            "view_ids": [],
            "topic_count": 10,
            "image_model_id": "flux-2-max",
            "image_notes": "The seabirds are above the water; the whale is below the surface.",
            "trigger": "SCHEDULE",
            "pipeline_version": "article-v1",
            "state": "SUCCEEDED",
            "steps": {},
            "verdict": {},
            "article": {},
            "result": {},
            "cost": {},
            "policy_snapshot": {},
            "error": {},
            "end_time": "2026-01-15T09:30:00Z"
          }
        ]
      },
      "EditorialGenerationCreate": {
        "type": "object",
        "description": "The `editorial_generations` fields a client may set on create.",
        "properties": {
          "kind": {
            "type": "string",
            "description": "What the run produces: `ARTICLE` \u2014 one slot's post, with its translations and cover where the policy names the agents; `TOPICS` \u2014 a batch of proposed topics for the backlog. Fixed after create.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "ARTICLE"
            ]
          },
          "slot_id": {
            "type": "string",
            "description": "The `editorial_slots` entry the run writes for. Required for an `ARTICLE` run and refused for a `TOPICS` run; the slot's content mode must be `AI_GENERATED`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          },
          "parts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which parts an `ARTICLE` run produces: `TEXT`, `TRANSLATIONS`, `IMAGE`. Empty \u2014 every part the policy enables, and the translations and the cover only for an article whose text verdict is `PASSED`. Named explicitly, the parts are produced whatever the verdict. On a drafted slot this is regeneration: the fields a person edited are kept and named on the step, and `TEXT` may be left out once a run has written the slot's article. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              [
                "TEXT",
                "TRANSLATIONS"
              ]
            ]
          },
          "view_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The views a `TRANSLATIONS` part covers, each one a view the policy would translate into; empty \u2014 all of them. Fixed after create.",
            "x-field-behavior": "IMMUTABLE"
          },
          "topic_count": {
            "type": "integer",
            "format": "int64",
            "description": "How many topics a `TOPICS` run asks for, between 1 and 30; defaults to the policy's `topic_batch_size`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              10
            ]
          },
          "image_model_id": {
            "type": "string",
            "description": "The `ai_models` entry the cover is drawn on for this run, in place of the image agent's `preferred_model_id`. Only on an `ARTICLE` run that draws the cover \u2014 `parts` naming `IMAGE`, or empty on a policy with both image agents; the model must be one the image agent can run on, and is refused with the reason otherwise. Kept by `:retry`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              "flux-2-max"
            ]
          },
          "image_notes": {
            "type": "string",
            "description": "A person's instructions for the cover of this run, at most 2000 characters. The image brief writer receives them as its `notes` variable, where its instruction declares one, and the image agent receives them appended to its prompt as they are. Only on a run that draws the cover, like `image_model_id`. Kept by `:retry`. Fixed after create.",
            "x-field-behavior": "IMMUTABLE",
            "examples": [
              "The seabirds are above the water; the whale is below the surface."
            ]
          },
          "request_id": {
            "type": "string",
            "description": "An idempotency key you choose, at most 64 characters. Creating with a key already used returns the run that key created instead of starting another.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "3f6c1b8e-6b7a-4f0e-9d53-2d8a0c1e7b42"
            ]
          }
        },
        "required": [
          "kind"
        ],
        "examples": [
          {
            "kind": "ARTICLE"
          }
        ]
      },
      "EditorialGenerationUpdate": {
        "type": "object",
        "description": "The `editorial_generations` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "kind": {
            "type": "string",
            "description": "What the run produces: `ARTICLE` \u2014 one slot's post, with its translations and cover where the policy names the agents; `TOPICS` \u2014 a batch of proposed topics for the backlog. Fixed after create.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "ARTICLE"
            ]
          },
          "request_id": {
            "type": "string",
            "description": "An idempotency key you choose, at most 64 characters. Creating with a key already used returns the run that key created instead of starting another.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY",
            "examples": [
              "3f6c1b8e-6b7a-4f0e-9d53-2d8a0c1e7b42"
            ]
          }
        },
        "examples": [
          {
            "kind": "ARTICLE"
          }
        ]
      },
      "EditorialPlan": {
        "type": "object",
        "description": "The publication rules of one website's editorial desk: on which days and at what local times posts go out, how far ahead the calendar is filled, how long before its date a slot becomes a draft, and what that draft inherits. There is one per website and it always exists \u2014 a website that has never configured one reads back the defaults, and the first Update is what stores it. What to write about lives in `editorial_topics`, and when each piece goes out in `editorial_slots`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/editorial_plan"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the desk is running. While it is false the calendar is not filled, no draft is prepared and nothing wakes up \u2014 the plan is kept, not executed.",
            "x-field-behavior": "REQUIRED"
          },
          "time_zone": {
            "type": "string",
            "description": "The IANA zone the schedule's wall-clock times are read in, so \"Monday 10:00\" stays 10:00 across a daylight-saving change instead of drifting an hour twice a year.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "America/Sao_Paulo"
            ]
          },
          "schedule": {
            "description": "When posts go out, as a list of `{\"weekday\", \"time_of_day\"}` rules. `weekday` is one of MONDAY\u2026SUNDAY and `time_of_day` is a local `HH:MM`. An empty list plans nothing.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              [
                {
                  "weekday": "MONDAY",
                  "time_of_day": "10:00"
                }
              ]
            ]
          },
          "planning_horizon_days": {
            "type": "integer",
            "format": "int64",
            "description": "How far ahead the calendar is filled, in days. The window rolls forward on its own, so a plan left alone always has about this much scheduled. Defaults to 30.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              30
            ]
          },
          "draft_lead_days": {
            "type": "integer",
            "format": "int64",
            "description": "How long before its date a slot turns into a draft, in days \u2014 the writing time the desk gives itself. Defaults to 3.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              3
            ]
          },
          "target_type": {
            "type": "string",
            "description": "What kind of content a slot produces. `blog_post` is the only kind this platform makes today, and the default; a slot may name a different one of its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "blog_post"
            ]
          },
          "content_mode": {
            "type": "string",
            "description": "Who fills a slot when its date comes near. `EMPTY_DRAFT` \u2014 the default \u2014 creates the draft and leaves the writing to a person; other modes are offered by the platform's producers, and a mode this website is not set up for is refused. A slot may override it for one date.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "EMPTY_DRAFT"
            ]
          },
          "default_category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_categories` a fresh draft is filed under when its topic names none of its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "default_tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_tags` a fresh draft carries when its topic names none of its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "default_author_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_authors` a fresh draft is credited to when its topic names no author of its own: one of them, chosen at random for each slot and kept if that slot is drafted again. List one author to credit every such draft to them.",
            "x-field-behavior": "OPTIONAL"
          },
          "notification_emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Who the desk writes to about its work, up to 20 addresses. They are stored trimmed and in lower case, without repeats. Left empty, the letters go to the owner of the account.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "editor@example.com"
              ]
            ]
          },
          "notification_events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the desk writes about: `TOPICS_PROPOSED` \u2014 new topics were suggested, `ARTICLE_DRAFTED` \u2014 a draft is ready, `ARTICLE_PUBLISHED` \u2014 an article went live, `FAILURE` \u2014 preparing or publishing an article failed, or the desk is held back. Never set, it is all four. An empty list turns the letters off.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "ARTICLE_DRAFTED",
                "FAILURE"
              ]
            ]
          },
          "next_tick_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the desk next looks at this website's calendar. It is the plan's liveness signal: a value in the past on an enabled plan means the schedule stalled and needs waking.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          }
        },
        "required": [
          "name"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/editorial_plan",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "enabled": true,
            "time_zone": "America/Sao_Paulo",
            "schedule": [
              {
                "weekday": "MONDAY",
                "time_of_day": "10:00"
              }
            ],
            "planning_horizon_days": 30,
            "draft_lead_days": 3,
            "target_type": "blog_post",
            "content_mode": "EMPTY_DRAFT",
            "default_category_ids": [],
            "default_tag_ids": [],
            "default_author_ids": [],
            "notification_emails": [
              "editor@example.com"
            ],
            "notification_events": [
              "ARTICLE_DRAFTED",
              "FAILURE"
            ],
            "next_tick_time": "2026-01-15T09:30:00Z"
          }
        ]
      },
      "EditorialPlanCreate": {
        "type": "object",
        "description": "The `editorial_plan` fields a client may set on create.",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the desk is running. While it is false the calendar is not filled, no draft is prepared and nothing wakes up \u2014 the plan is kept, not executed.",
            "x-field-behavior": "REQUIRED"
          },
          "time_zone": {
            "type": "string",
            "description": "The IANA zone the schedule's wall-clock times are read in, so \"Monday 10:00\" stays 10:00 across a daylight-saving change instead of drifting an hour twice a year.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "America/Sao_Paulo"
            ]
          },
          "schedule": {
            "description": "When posts go out, as a list of `{\"weekday\", \"time_of_day\"}` rules. `weekday` is one of MONDAY\u2026SUNDAY and `time_of_day` is a local `HH:MM`. An empty list plans nothing.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              [
                {
                  "weekday": "MONDAY",
                  "time_of_day": "10:00"
                }
              ]
            ]
          },
          "planning_horizon_days": {
            "type": "integer",
            "format": "int64",
            "description": "How far ahead the calendar is filled, in days. The window rolls forward on its own, so a plan left alone always has about this much scheduled. Defaults to 30.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              30
            ]
          },
          "draft_lead_days": {
            "type": "integer",
            "format": "int64",
            "description": "How long before its date a slot turns into a draft, in days \u2014 the writing time the desk gives itself. Defaults to 3.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              3
            ]
          },
          "target_type": {
            "type": "string",
            "description": "What kind of content a slot produces. `blog_post` is the only kind this platform makes today, and the default; a slot may name a different one of its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "blog_post"
            ]
          },
          "content_mode": {
            "type": "string",
            "description": "Who fills a slot when its date comes near. `EMPTY_DRAFT` \u2014 the default \u2014 creates the draft and leaves the writing to a person; other modes are offered by the platform's producers, and a mode this website is not set up for is refused. A slot may override it for one date.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "EMPTY_DRAFT"
            ]
          },
          "default_category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_categories` a fresh draft is filed under when its topic names none of its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "default_tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_tags` a fresh draft carries when its topic names none of its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "default_author_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_authors` a fresh draft is credited to when its topic names no author of its own: one of them, chosen at random for each slot and kept if that slot is drafted again. List one author to credit every such draft to them.",
            "x-field-behavior": "OPTIONAL"
          },
          "notification_emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Who the desk writes to about its work, up to 20 addresses. They are stored trimmed and in lower case, without repeats. Left empty, the letters go to the owner of the account.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "editor@example.com"
              ]
            ]
          },
          "notification_events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the desk writes about: `TOPICS_PROPOSED` \u2014 new topics were suggested, `ARTICLE_DRAFTED` \u2014 a draft is ready, `ARTICLE_PUBLISHED` \u2014 an article went live, `FAILURE` \u2014 preparing or publishing an article failed, or the desk is held back. Never set, it is all four. An empty list turns the letters off.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "ARTICLE_DRAFTED",
                "FAILURE"
              ]
            ]
          }
        },
        "required": [
          "enabled",
          "time_zone",
          "schedule"
        ],
        "examples": [
          {
            "enabled": true,
            "time_zone": "America/Sao_Paulo",
            "schedule": [
              {
                "weekday": "MONDAY",
                "time_of_day": "10:00"
              }
            ]
          }
        ]
      },
      "EditorialPlanUpdate": {
        "type": "object",
        "description": "The `editorial_plan` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the desk is running. While it is false the calendar is not filled, no draft is prepared and nothing wakes up \u2014 the plan is kept, not executed.",
            "x-field-behavior": "REQUIRED"
          },
          "time_zone": {
            "type": "string",
            "description": "The IANA zone the schedule's wall-clock times are read in, so \"Monday 10:00\" stays 10:00 across a daylight-saving change instead of drifting an hour twice a year.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "America/Sao_Paulo"
            ]
          },
          "schedule": {
            "description": "When posts go out, as a list of `{\"weekday\", \"time_of_day\"}` rules. `weekday` is one of MONDAY\u2026SUNDAY and `time_of_day` is a local `HH:MM`. An empty list plans nothing.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              [
                {
                  "weekday": "MONDAY",
                  "time_of_day": "10:00"
                }
              ]
            ]
          },
          "planning_horizon_days": {
            "type": "integer",
            "format": "int64",
            "description": "How far ahead the calendar is filled, in days. The window rolls forward on its own, so a plan left alone always has about this much scheduled. Defaults to 30.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              30
            ]
          },
          "draft_lead_days": {
            "type": "integer",
            "format": "int64",
            "description": "How long before its date a slot turns into a draft, in days \u2014 the writing time the desk gives itself. Defaults to 3.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              3
            ]
          },
          "target_type": {
            "type": "string",
            "description": "What kind of content a slot produces. `blog_post` is the only kind this platform makes today, and the default; a slot may name a different one of its own.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "blog_post"
            ]
          },
          "content_mode": {
            "type": "string",
            "description": "Who fills a slot when its date comes near. `EMPTY_DRAFT` \u2014 the default \u2014 creates the draft and leaves the writing to a person; other modes are offered by the platform's producers, and a mode this website is not set up for is refused. A slot may override it for one date.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "EMPTY_DRAFT"
            ]
          },
          "default_category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_categories` a fresh draft is filed under when its topic names none of its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "default_tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_tags` a fresh draft carries when its topic names none of its own.",
            "x-field-behavior": "OPTIONAL"
          },
          "default_author_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_authors` a fresh draft is credited to when its topic names no author of its own: one of them, chosen at random for each slot and kept if that slot is drafted again. List one author to credit every such draft to them.",
            "x-field-behavior": "OPTIONAL"
          },
          "notification_emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Who the desk writes to about its work, up to 20 addresses. They are stored trimmed and in lower case, without repeats. Left empty, the letters go to the owner of the account.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "editor@example.com"
              ]
            ]
          },
          "notification_events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the desk writes about: `TOPICS_PROPOSED` \u2014 new topics were suggested, `ARTICLE_DRAFTED` \u2014 a draft is ready, `ARTICLE_PUBLISHED` \u2014 an article went live, `FAILURE` \u2014 preparing or publishing an article failed, or the desk is held back. Never set, it is all four. An empty list turns the letters off.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "ARTICLE_DRAFTED",
                "FAILURE"
              ]
            ]
          }
        },
        "examples": [
          {
            "enabled": true,
            "time_zone": "America/Sao_Paulo",
            "schedule": [
              {
                "weekday": "MONDAY",
                "time_of_day": "10:00"
              }
            ]
          }
        ]
      },
      "EditorialSlot": {
        "type": "object",
        "description": "One cell of the content calendar: a moment, the topic that fills it, and the content it produced. A slot is created by the desk from the plan's schedule, or by hand for a date you want yourself. Its moment is unique, which is how a date you chose is never overwritten \u2014 the desk simply never plans on a taken moment. `:skip` drops the date and returns its topic to the backlog, `:materialize` prepares the draft now rather than waiting, and `:publish` makes that draft live.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/editorial_slots/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "scheduled_time": {
            "type": "string",
            "format": "date-time",
            "description": "When this piece goes out. Unique across the website \u2014 one slot per moment \u2014 and the order the calendar is read in. Moving a slot is a write of this field, and it takes the slot out of the desk's hands.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-10-05T13:00:00Z"
            ]
          },
          "topic_id": {
            "type": "string",
            "description": "The `editorial_topics` resource filling this slot. Empty on a slot someone put on the calendar with a title and no backlog entry.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "title": {
            "type": "string",
            "description": "The headline this slot stands for, copied from its topic when the slot was made. It is a snapshot, so a month of calendar draws without reading every topic \u2014 and so a topic renamed later does not rewrite a slot that already produced a draft.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "target_type": {
            "type": "string",
            "description": "What this slot produces. Defaults to the plan's and cannot be changed afterwards: a slot that switched kind mid-flight would leave its draft behind with nothing pointing at it.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "blog_post"
            ]
          },
          "target_id": {
            "type": "string",
            "description": "The `blog_posts` resource this slot created. It is also what makes preparing a draft safe to repeat \u2014 a slot that already names its post never gets a second one.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          },
          "status": {
            "type": "string",
            "description": "Where the slot stands: PLANNED before its draft exists, GENERATING while a producer is writing it, DRAFTED once it does, PUBLISHED once that post is live, SKIPPED if the date was dropped, FAILED if preparing the draft did not work. FAILED is retried where the retry is free, and left to you where it is not.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "PLANNED"
            ]
          },
          "origin": {
            "type": "string",
            "description": "AUTO while the slot is the desk's to manage, MANUAL once a person created or edited it \u2014 after which the desk leaves it alone for good. This is the whole of \"a person outranks the schedule\".",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "AUTO"
            ]
          },
          "last_error": {
            "type": "string",
            "description": "Why the last attempt to prepare this slot's draft did not work. Cleared as soon as one succeeds, so it always describes the present.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "content_mode": {
            "type": "string",
            "description": "Who fills this one slot, overriding the plan's `content_mode` for this date alone \u2014 \"I am writing this Friday myself\". Absent, the plan decides. It can be set while the slot is still PLANNED or FAILED, not once its draft exists.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "EMPTY_DRAFT"
            ]
          },
          "generation_id": {
            "type": "string",
            "description": "The latest `editorial_generations` run producing this slot's content, when a producer other than a person is writing it. Absent on a slot nobody generated.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "review_verdict": {
            "type": "string",
            "description": "What the producer's own check made of the content: PASSED, or NEEDS_REVIEW when a person should read it before it goes out. A snapshot of the run's verdict, kept here so a month of calendar draws its badges without reading every run.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "PASSED"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/editorial_slots/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "scheduled_time": "2026-10-05T13:00:00Z",
            "topic_id": "string",
            "title": "string",
            "target_type": "blog_post",
            "target_id": "string",
            "status": "PLANNED",
            "origin": "AUTO",
            "last_error": "string",
            "content_mode": "EMPTY_DRAFT",
            "generation_id": "string",
            "review_verdict": "PASSED"
          }
        ]
      },
      "EditorialSlotCreate": {
        "type": "object",
        "description": "The `editorial_slots` fields a client may set on create.",
        "properties": {
          "scheduled_time": {
            "type": "string",
            "format": "date-time",
            "description": "When this piece goes out. Unique across the website \u2014 one slot per moment \u2014 and the order the calendar is read in. Moving a slot is a write of this field, and it takes the slot out of the desk's hands.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-10-05T13:00:00Z"
            ]
          },
          "topic_id": {
            "type": "string",
            "description": "The `editorial_topics` resource filling this slot. Empty on a slot someone put on the calendar with a title and no backlog entry.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "title": {
            "type": "string",
            "description": "The headline this slot stands for, copied from its topic when the slot was made. It is a snapshot, so a month of calendar draws without reading every topic \u2014 and so a topic renamed later does not rewrite a slot that already produced a draft.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "target_type": {
            "type": "string",
            "description": "What this slot produces. Defaults to the plan's and cannot be changed afterwards: a slot that switched kind mid-flight would leave its draft behind with nothing pointing at it.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "blog_post"
            ]
          },
          "content_mode": {
            "type": "string",
            "description": "Who fills this one slot, overriding the plan's `content_mode` for this date alone \u2014 \"I am writing this Friday myself\". Absent, the plan decides. It can be set while the slot is still PLANNED or FAILED, not once its draft exists.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "EMPTY_DRAFT"
            ]
          }
        },
        "required": [
          "scheduled_time"
        ],
        "examples": [
          {
            "scheduled_time": "2026-10-05T13:00:00Z"
          }
        ]
      },
      "EditorialSlotUpdate": {
        "type": "object",
        "description": "The `editorial_slots` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "scheduled_time": {
            "type": "string",
            "format": "date-time",
            "description": "When this piece goes out. Unique across the website \u2014 one slot per moment \u2014 and the order the calendar is read in. Moving a slot is a write of this field, and it takes the slot out of the desk's hands.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-10-05T13:00:00Z"
            ]
          },
          "topic_id": {
            "type": "string",
            "description": "The `editorial_topics` resource filling this slot. Empty on a slot someone put on the calendar with a title and no backlog entry.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "title": {
            "type": "string",
            "description": "The headline this slot stands for, copied from its topic when the slot was made. It is a snapshot, so a month of calendar draws without reading every topic \u2014 and so a topic renamed later does not rewrite a slot that already produced a draft.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "content_mode": {
            "type": "string",
            "description": "Who fills this one slot, overriding the plan's `content_mode` for this date alone \u2014 \"I am writing this Friday myself\". Absent, the plan decides. It can be set while the slot is still PLANNED or FAILED, not once its draft exists.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "EMPTY_DRAFT"
            ]
          }
        },
        "examples": [
          {
            "scheduled_time": "2026-10-05T13:00:00Z"
          }
        ]
      },
      "EditorialTopic": {
        "type": "object",
        "description": "One item of the backlog: something this website intends to write about. A topic outlives the article it becomes \u2014 it records which slot consumed it, and one that was turned down stays turned down instead of resurfacing the next time the calendar is filled. `:batch_create` adds a whole list in one call, `:reject` and `:restore` move it in and out of the backlog, and `:accept` takes in an idea the desk's AI proposed.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/editorial_topics/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "title": {
            "type": "string",
            "description": "What the article is about, in a line. It becomes the headline of the draft the topic turns into, and the label the calendar shows for its slot.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "How we pack a piano"
            ]
          },
          "brief": {
            "type": "string",
            "description": "The editor's note on what the article should say. It is copied into the draft's teaser, so whoever writes the post opens it and finds the assignment already there.",
            "x-field-behavior": "OPTIONAL"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The search terms this article is meant to answer \u2014 a note to the writer, not something the platform acts on.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_categories` this topic's draft is filed under. Set, it replaces the plan's defaults outright rather than adding to them.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_tags` this topic's draft carries, with the same rule as `category_ids`: set, it replaces the plan's defaults.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "author_id": {
            "type": "string",
            "description": "The `blog_authors` resource this topic's draft is credited to, instead of the plan's default.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "Which topic is taken next: higher goes first, and equals are taken oldest first. Sort by it inside a `status` filter \u2014 that is the pair an index backs.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              10
            ]
          },
          "status": {
            "type": "string",
            "description": "Where the topic stands: PROPOSED while an idea the desk's AI suggested waits for a person, CANDIDATE while it waits in the backlog, PLANNED once a slot holds it, USED once that slot's post is live, REJECTED if it was turned down. Moved by `:accept`, `:reject`, `:restore` and by the desk itself, never by writing this field.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "CANDIDATE"
            ]
          },
          "slot_id": {
            "type": "string",
            "description": "The `editorial_slots` resource holding this topic while it is PLANNED or USED. Empty while it is still in the backlog.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          },
          "origin": {
            "type": "string",
            "description": "Who put the topic on the list: MANUAL for one a person entered, SUGGESTED for one a `TOPICS` run of `editorial_generations` proposed.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "MANUAL"
            ]
          },
          "generation_id": {
            "type": "string",
            "description": "The `editorial_generations` run that proposed this topic. Absent on a topic a person entered. Which topics a run proposed is that run's own `result`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "64ff1f77aa01b2c3d4e5f607"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/editorial_topics/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "title": "How we pack a piano",
            "brief": "string",
            "keywords": [],
            "category_ids": [],
            "tag_ids": [],
            "author_id": "string",
            "priority": 10,
            "status": "CANDIDATE",
            "slot_id": "string",
            "origin": "MANUAL",
            "generation_id": "64ff1f77aa01b2c3d4e5f607"
          }
        ]
      },
      "EditorialTopicCreate": {
        "type": "object",
        "description": "The `editorial_topics` fields a client may set on create.",
        "properties": {
          "title": {
            "type": "string",
            "description": "What the article is about, in a line. It becomes the headline of the draft the topic turns into, and the label the calendar shows for its slot.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "How we pack a piano"
            ]
          },
          "brief": {
            "type": "string",
            "description": "The editor's note on what the article should say. It is copied into the draft's teaser, so whoever writes the post opens it and finds the assignment already there.",
            "x-field-behavior": "OPTIONAL"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The search terms this article is meant to answer \u2014 a note to the writer, not something the platform acts on.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_categories` this topic's draft is filed under. Set, it replaces the plan's defaults outright rather than adding to them.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_tags` this topic's draft carries, with the same rule as `category_ids`: set, it replaces the plan's defaults.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "author_id": {
            "type": "string",
            "description": "The `blog_authors` resource this topic's draft is credited to, instead of the plan's default.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "Which topic is taken next: higher goes first, and equals are taken oldest first. Sort by it inside a `status` filter \u2014 that is the pair an index backs.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              10
            ]
          }
        },
        "required": [
          "title"
        ],
        "examples": [
          {
            "title": "How we pack a piano"
          }
        ]
      },
      "EditorialTopicUpdate": {
        "type": "object",
        "description": "The `editorial_topics` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "title": {
            "type": "string",
            "description": "What the article is about, in a line. It becomes the headline of the draft the topic turns into, and the label the calendar shows for its slot.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "How we pack a piano"
            ]
          },
          "brief": {
            "type": "string",
            "description": "The editor's note on what the article should say. It is copied into the draft's teaser, so whoever writes the post opens it and finds the assignment already there.",
            "x-field-behavior": "OPTIONAL"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The search terms this article is meant to answer \u2014 a note to the writer, not something the platform acts on.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_categories` this topic's draft is filed under. Set, it replaces the plan's defaults outright rather than adding to them.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The `blog_tags` this topic's draft carries, with the same rule as `category_ids`: set, it replaces the plan's defaults.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "author_id": {
            "type": "string",
            "description": "The `blog_authors` resource this topic's draft is credited to, instead of the plan's default.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "priority": {
            "type": "integer",
            "format": "int64",
            "description": "Which topic is taken next: higher goes first, and equals are taken oldest first. Sort by it inside a `status` filter \u2014 that is the pair an index backs.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              10
            ]
          }
        },
        "examples": [
          {
            "title": "How we pack a piano"
          }
        ]
      },
      "EmailTemplate": {
        "type": "object",
        "description": "The text of one kind of email a website sends: a subject and a plain-text body with `{{placeholders}}`, written in the website's default language. The platform creates one template of each kind for every website, marked `is_default`, and a website may add its own. What another view says instead lives in the template's `views` overlays, and a field a view does not override is sent as written here.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/email_templates/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "kind": {
            "type": "string",
            "description": "Which email the template is for: `feedback` \u2014 the message a website's contact form sends to its notification addresses; `customer_welcome` \u2014 what a visitor receives after registering an account on the website; `customer_password_reset` \u2014 the link a customer follows to choose a new password; `editorial_topics_proposed`, `editorial_article_drafted`, `editorial_article_published` and `editorial_failure` \u2014 what the editorial desk sends the notification addresses of its plan when it has proposed topics, a draft is ready, an article has gone live, or something went wrong. The kind decides which placeholders the text may use. Required on Create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "feedback"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The template's name in the admin. A label for the people who edit it \u2014 the email's recipient never sees it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Contact form notification"
            ]
          },
          "subject": {
            "type": "string",
            "description": "The email's subject line, with `{{placeholders}}` as in `body`. It stays one line: a line break a placeholder's value brings in is sent as a space.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "New feedback: {{page_title}}"
            ]
          },
          "body": {
            "type": "string",
            "description": "The email's text: plain text, where an empty line starts a new paragraph and `{{placeholder}}` is replaced by its value when the email is sent. There is no HTML to write \u2014 the platform sets the text in its own layout. A placeholder the kind does not have is replaced by nothing. A `feedback` template may use `{{name}}`, `{{email}}` and `{{phone}}` \u2014 what the visitor entered, empty when the form does not ask for it \u2014 `{{message}}`, what they wrote, `{{page_title}}`, the title of the contact page in the language of its view, and `{{website_name}}`. Both customer kinds may use `{{display_name}}` \u2014 the customer's name, or their email address when they gave none \u2014 `{{email}}`, the address they sign in with, and `{{website_name}}`; a `customer_welcome` template also `{{account_url}}`, the address of their account page, and a `customer_password_reset` template `{{reset_url}}`, the one-time link to the page where they choose a new password. A reset text that leaves `{{reset_url}}` out is not sent: the platform's own English email goes instead. Every editorial kind may use `{{website_name}}`. An `editorial_topics_proposed` template also `{{topic_count}}`, `{{topics}}` \u2014 the titles of the new topics, one per line \u2014 `{{duplicates_skipped}}`, `{{topic_status}}` (`PROPOSED` or `CANDIDATE`) and `{{topics_url}}`; an `editorial_article_drafted` template `{{title}}`, `{{scheduled_time}}` (`YYYY-MM-DD HH:MM` in the plan's time zone), `{{verdict}}`, `{{score}}`, `{{issues}}` \u2014 one per line \u2014 and `{{cost}}`, these four empty for a draft the AI did not write, and `{{edit_url}}`, `{{generation_url}}` and `{{calendar_url}}`; an `editorial_article_published` template `{{title}}`, `{{public_url}}`, the article's address on the website, `{{edit_url}}` and `{{calendar_url}}`; an `editorial_failure` template `{{title}}` and `{{scheduled_time}}`, empty when no single article is concerned, `{{stage}}` \u2014 the step that went wrong \u2014 `{{reason}}`, its code, `{{message}}`, `{{issues}}` and `{{url}}`, the run's page or the calendar. The editorial links lead into the admin, and are empty when the platform has no address of it configured.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "{{name}} ({{email}}) wrote: {{message}}"
            ]
          },
          "is_default": {
            "type": "boolean",
            "description": "Whether this is the template the platform created for its kind \u2014 the one an email of that kind is sent from when the website has chosen no other. There is one per kind, only the platform sets it, and it cannot be deleted.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/email_templates/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "kind": "feedback",
            "display_name": "Contact form notification",
            "subject": "New feedback: {{page_title}}",
            "body": "{{name}} ({{email}}) wrote: {{message}}",
            "is_default": true
          }
        ]
      },
      "EmailTemplateCreate": {
        "type": "object",
        "description": "The `email_templates` fields a client may set on create.",
        "properties": {
          "kind": {
            "type": "string",
            "description": "Which email the template is for: `feedback` \u2014 the message a website's contact form sends to its notification addresses; `customer_welcome` \u2014 what a visitor receives after registering an account on the website; `customer_password_reset` \u2014 the link a customer follows to choose a new password; `editorial_topics_proposed`, `editorial_article_drafted`, `editorial_article_published` and `editorial_failure` \u2014 what the editorial desk sends the notification addresses of its plan when it has proposed topics, a draft is ready, an article has gone live, or something went wrong. The kind decides which placeholders the text may use. Required on Create and fixed afterwards.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "feedback"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The template's name in the admin. A label for the people who edit it \u2014 the email's recipient never sees it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Contact form notification"
            ]
          },
          "subject": {
            "type": "string",
            "description": "The email's subject line, with `{{placeholders}}` as in `body`. It stays one line: a line break a placeholder's value brings in is sent as a space.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "New feedback: {{page_title}}"
            ]
          },
          "body": {
            "type": "string",
            "description": "The email's text: plain text, where an empty line starts a new paragraph and `{{placeholder}}` is replaced by its value when the email is sent. There is no HTML to write \u2014 the platform sets the text in its own layout. A placeholder the kind does not have is replaced by nothing. A `feedback` template may use `{{name}}`, `{{email}}` and `{{phone}}` \u2014 what the visitor entered, empty when the form does not ask for it \u2014 `{{message}}`, what they wrote, `{{page_title}}`, the title of the contact page in the language of its view, and `{{website_name}}`. Both customer kinds may use `{{display_name}}` \u2014 the customer's name, or their email address when they gave none \u2014 `{{email}}`, the address they sign in with, and `{{website_name}}`; a `customer_welcome` template also `{{account_url}}`, the address of their account page, and a `customer_password_reset` template `{{reset_url}}`, the one-time link to the page where they choose a new password. A reset text that leaves `{{reset_url}}` out is not sent: the platform's own English email goes instead. Every editorial kind may use `{{website_name}}`. An `editorial_topics_proposed` template also `{{topic_count}}`, `{{topics}}` \u2014 the titles of the new topics, one per line \u2014 `{{duplicates_skipped}}`, `{{topic_status}}` (`PROPOSED` or `CANDIDATE`) and `{{topics_url}}`; an `editorial_article_drafted` template `{{title}}`, `{{scheduled_time}}` (`YYYY-MM-DD HH:MM` in the plan's time zone), `{{verdict}}`, `{{score}}`, `{{issues}}` \u2014 one per line \u2014 and `{{cost}}`, these four empty for a draft the AI did not write, and `{{edit_url}}`, `{{generation_url}}` and `{{calendar_url}}`; an `editorial_article_published` template `{{title}}`, `{{public_url}}`, the article's address on the website, `{{edit_url}}` and `{{calendar_url}}`; an `editorial_failure` template `{{title}}` and `{{scheduled_time}}`, empty when no single article is concerned, `{{stage}}` \u2014 the step that went wrong \u2014 `{{reason}}`, its code, `{{message}}`, `{{issues}}` and `{{url}}`, the run's page or the calendar. The editorial links lead into the admin, and are empty when the platform has no address of it configured.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "{{name}} ({{email}}) wrote: {{message}}"
            ]
          }
        },
        "required": [
          "display_name",
          "subject",
          "body"
        ],
        "examples": [
          {
            "display_name": "Contact form notification",
            "subject": "New feedback: {{page_title}}",
            "body": "{{name}} ({{email}}) wrote: {{message}}"
          }
        ]
      },
      "EmailTemplateUpdate": {
        "type": "object",
        "description": "The `email_templates` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The template's name in the admin. A label for the people who edit it \u2014 the email's recipient never sees it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Contact form notification"
            ]
          },
          "subject": {
            "type": "string",
            "description": "The email's subject line, with `{{placeholders}}` as in `body`. It stays one line: a line break a placeholder's value brings in is sent as a space.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "New feedback: {{page_title}}"
            ]
          },
          "body": {
            "type": "string",
            "description": "The email's text: plain text, where an empty line starts a new paragraph and `{{placeholder}}` is replaced by its value when the email is sent. There is no HTML to write \u2014 the platform sets the text in its own layout. A placeholder the kind does not have is replaced by nothing. A `feedback` template may use `{{name}}`, `{{email}}` and `{{phone}}` \u2014 what the visitor entered, empty when the form does not ask for it \u2014 `{{message}}`, what they wrote, `{{page_title}}`, the title of the contact page in the language of its view, and `{{website_name}}`. Both customer kinds may use `{{display_name}}` \u2014 the customer's name, or their email address when they gave none \u2014 `{{email}}`, the address they sign in with, and `{{website_name}}`; a `customer_welcome` template also `{{account_url}}`, the address of their account page, and a `customer_password_reset` template `{{reset_url}}`, the one-time link to the page where they choose a new password. A reset text that leaves `{{reset_url}}` out is not sent: the platform's own English email goes instead. Every editorial kind may use `{{website_name}}`. An `editorial_topics_proposed` template also `{{topic_count}}`, `{{topics}}` \u2014 the titles of the new topics, one per line \u2014 `{{duplicates_skipped}}`, `{{topic_status}}` (`PROPOSED` or `CANDIDATE`) and `{{topics_url}}`; an `editorial_article_drafted` template `{{title}}`, `{{scheduled_time}}` (`YYYY-MM-DD HH:MM` in the plan's time zone), `{{verdict}}`, `{{score}}`, `{{issues}}` \u2014 one per line \u2014 and `{{cost}}`, these four empty for a draft the AI did not write, and `{{edit_url}}`, `{{generation_url}}` and `{{calendar_url}}`; an `editorial_article_published` template `{{title}}`, `{{public_url}}`, the article's address on the website, `{{edit_url}}` and `{{calendar_url}}`; an `editorial_failure` template `{{title}}` and `{{scheduled_time}}`, empty when no single article is concerned, `{{stage}}` \u2014 the step that went wrong \u2014 `{{reason}}`, its code, `{{message}}`, `{{issues}}` and `{{url}}`, the run's page or the calendar. The editorial links lead into the admin, and are empty when the platform has no address of it configured.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "{{name}} ({{email}}) wrote: {{message}}"
            ]
          }
        },
        "examples": [
          {
            "display_name": "Contact form notification",
            "subject": "New feedback: {{page_title}}",
            "body": "{{name}} ({{email}}) wrote: {{message}}"
          }
        ]
      },
      "EmailTemplateView": {
        "type": "object",
        "description": "What one view's email says instead of the template: its subject and text in that view's language. It works like every other overlay \u2014 optional fields, a fallback to the template, and `overridden` deciding which of them this view claims \u2014 with one addition: an Update of an overlay that does not exist yet creates it, so saving a view's text is one call whether or not it had one.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/email_templates/9c2d40f7e1ab/views/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id. The overlay is addressed by its view, not by this.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "email_template_id": {
            "type": "string",
            "description": "The template this overlay belongs to. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The fields this view actually overrides \u2014 `subject`, `body`, or both. A field not listed falls back along the view's fallback chain to the template itself, whatever value is stored for it here.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "subject",
                "body"
              ]
            ]
          },
          "subject": {
            "type": "string",
            "description": "This view's subject line, with the template's placeholders.",
            "x-field-behavior": "OPTIONAL"
          },
          "body": {
            "type": "string",
            "description": "This view's text, written like the template's `body`.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/email_templates/9c2d40f7e1ab/views/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "email_template_id": "string",
            "view_id": "string",
            "overridden": [
              "subject",
              "body"
            ],
            "subject": "string",
            "body": "string"
          }
        ]
      },
      "EmailTemplateViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The fields this view actually overrides \u2014 `subject`, `body`, or both. A field not listed falls back along the view's fallback chain to the template itself, whatever value is stored for it here.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "subject",
                "body"
              ]
            ]
          },
          "subject": {
            "type": "string",
            "description": "This view's subject line, with the template's placeholders.",
            "x-field-behavior": "OPTIONAL"
          },
          "body": {
            "type": "string",
            "description": "This view's text, written like the template's `body`.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "subject",
              "body"
            ],
            "subject": "string"
          }
        ]
      },
      "EmailTemplateViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The fields this view actually overrides \u2014 `subject`, `body`, or both. A field not listed falls back along the view's fallback chain to the template itself, whatever value is stored for it here.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "subject",
                "body"
              ]
            ]
          },
          "subject": {
            "type": "string",
            "description": "This view's subject line, with the template's placeholders.",
            "x-field-behavior": "OPTIONAL"
          },
          "body": {
            "type": "string",
            "description": "This view's text, written like the template's `body`.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "subject",
              "body"
            ],
            "subject": "string"
          }
        ]
      },
      "MediaFolder": {
        "type": "object",
        "description": "A folder of the media library. Folders are a tree: `parent_id` names the one above, `path`, `level` and `sort_order` are maintained by the server, and the shape is changed with `:move` rather than by writing those fields. A file's folder is the `folder_id` on the file itself.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/media_folders/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The folder's name, as the media library shows it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Product photos"
            ]
          },
          "parent_id": {
            "type": "string",
            "description": "The folder this one sits in; empty at the root. Settable on create and immutable afterwards \u2014 moving a folder is `:move`.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true
          },
          "path": {
            "type": "string",
            "description": "The folder's position in the tree, as the ids of its ancestors and its own. Sorting by it renders the whole tree in one page, which is why it is the default order.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The folder's position among its siblings. Set by `:move`, never by a write.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-sortable": true
          },
          "level": {
            "type": "integer",
            "format": "int64",
            "description": "How deep the folder sits, counting the root as 0. Server-maintained with the rest of the tree bookkeeping.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/media_folders/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Product photos",
            "parent_id": "string",
            "path": "string",
            "sort_order": 0,
            "level": 0
          }
        ]
      },
      "MediaFolderCreate": {
        "type": "object",
        "description": "The `media_folders` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The folder's name, as the media library shows it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Product photos"
            ]
          },
          "parent_id": {
            "type": "string",
            "description": "The folder this one sits in; empty at the root. Settable on create and immutable afterwards \u2014 moving a folder is `:move`.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "required": [
          "display_name"
        ],
        "examples": [
          {
            "display_name": "Product photos"
          }
        ]
      },
      "MediaFolderUpdate": {
        "type": "object",
        "description": "The `media_folders` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The folder's name, as the media library shows it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Product photos"
            ]
          }
        },
        "examples": [
          {
            "display_name": "Product photos"
          }
        ]
      },
      "Media": {
        "type": "object",
        "description": "A file in the website's media library. Create is a `multipart/form-data` upload \u2014 everything but `alt_text`, `title` and `folder_id` is read off the file itself \u2014 and the bytes come back from `GET /engine-api/v1/websites/{website_id}/media/{id}`, which resizes and re-encodes on the fly \u2014 the same URL a rendered page asks for.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/media/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "filename": {
            "type": "string",
            "description": "The name the file is stored under, made unique on upload. This is the one that appears in the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "hero-2026-01.jpg"
            ]
          },
          "original_filename": {
            "type": "string",
            "description": "The name the file arrived with, kept so a person can recognise their own upload.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Hero shot (final).jpg"
            ]
          },
          "mime_type": {
            "type": "string",
            "description": "The stored file's media type, detected on upload. `filter=mime_type:\"image/\"` is how you ask for pictures by family.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "image/jpeg"
            ]
          },
          "storage_path": {
            "type": "string",
            "description": "Where the bytes live in the platform's object store. Internal bookkeeping \u2014 fetch the file through its media URL, not through this.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "file_size": {
            "type": "integer",
            "format": "int64",
            "description": "Size of the stored original, in bytes. A transformed variant is smaller and is not counted here.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              184320
            ]
          },
          "is_image": {
            "type": "boolean",
            "description": "Whether the file is an image, and therefore whether the `w`/`h`/`crop`/`q`/`fmt` transforms apply to it.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true
          },
          "width": {
            "type": "integer",
            "format": "int64",
            "description": "Width of the stored original in pixels. Meaningful only when `is_image` is true.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1920
            ]
          },
          "height": {
            "type": "integer",
            "format": "int64",
            "description": "Height of the stored original in pixels. Meaningful only when `is_image` is true.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              1080
            ]
          },
          "alt_text": {
            "type": "string",
            "description": "The alternative text rendered with the picture. It is what a screen reader announces, so it belongs on every image that carries meaning.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "title": {
            "type": "string",
            "description": "A human label for the file in the media library.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "folder_id": {
            "type": "string",
            "description": "The `media_folders` resource this file sits in. `filter=folder_id = null` is the library's root.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/media/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "filename": "hero-2026-01.jpg",
            "original_filename": "Hero shot (final).jpg",
            "mime_type": "image/jpeg",
            "storage_path": "string",
            "file_size": 184320,
            "is_image": true,
            "width": 1920,
            "height": 1080,
            "alt_text": "string",
            "title": "string",
            "folder_id": "string"
          }
        ]
      },
      "MediaCreate": {
        "type": "object",
        "description": "The `media` fields a client may set on create.",
        "properties": {
          "alt_text": {
            "type": "string",
            "description": "The alternative text rendered with the picture. It is what a screen reader announces, so it belongs on every image that carries meaning.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "title": {
            "type": "string",
            "description": "A human label for the file in the media library.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "folder_id": {
            "type": "string",
            "description": "The `media_folders` resource this file sits in. `filter=folder_id = null` is the library's root.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "examples": [
          {
            "alt_text": "string",
            "title": "string"
          }
        ]
      },
      "MediaUpdate": {
        "type": "object",
        "description": "The `media` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "alt_text": {
            "type": "string",
            "description": "The alternative text rendered with the picture. It is what a screen reader announces, so it belongs on every image that carries meaning.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "title": {
            "type": "string",
            "description": "A human label for the file in the media library.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "folder_id": {
            "type": "string",
            "description": "The `media_folders` resource this file sits in. `filter=folder_id = null` is the library's root.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "examples": [
          {
            "alt_text": "string",
            "title": "string"
          }
        ]
      },
      "MenuItem": {
        "type": "object",
        "description": "One entry of a menu. What it points at is `type`, and `type` decides which of the target fields is read \u2014 a link to a page carries `cms_page_id`, not a URL, so the menu survives the page being renamed or translated. Items nest: `parent_id` is set on create, and the shape and the order are changed with `:move` afterwards.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/menus/9c2d40f7e1ab/items/1b7e5a03c9d2"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "1b7e5a03c9d2"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "menu_id": {
            "type": "string",
            "description": "The menu this item belongs to. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "title": {
            "type": "string",
            "description": "The text of the link, as the menu renders it.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Our services"
            ]
          },
          "type": {
            "type": "string",
            "description": "What the item points at, which decides which of the fields below is read: `TEXT` (a heading with no link), `URL`, `CMS_PAGE`, `RAW_HTML`, `BLOG`, `BLOG_CATEGORY`, `BLOG_AUTHOR`, `BLOG_POST`, `BLOG_TAG` or `FEEDBACK_FORM`.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "CMS_PAGE"
            ]
          },
          "url": {
            "type": "string",
            "description": "The address a `URL` item points at. Anything else \u2014 a page, a category, a post \u2014 is linked by its id below, so the URL follows the resource when its slug or its view changes.",
            "x-field-behavior": "OPTIONAL"
          },
          "cms_page_id": {
            "type": "string",
            "description": "The page a `CMS_PAGE` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_category_id": {
            "type": "string",
            "description": "The category a `BLOG_CATEGORY` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_author_id": {
            "type": "string",
            "description": "The author a `BLOG_AUTHOR` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_post_id": {
            "type": "string",
            "description": "The post a `BLOG_POST` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_tag_id": {
            "type": "string",
            "description": "The tag a `BLOG_TAG` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "parent_id": {
            "type": "string",
            "description": "The item this one nests under; empty at the top level. Settable on create and immutable afterwards \u2014 re-nesting is `:move`.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true
          },
          "path": {
            "type": "string",
            "description": "The item's position in the menu tree, as the ids of its ancestors and its own. Server-generated: sending it is an error rather than a no-op.",
            "x-field-behavior": "IMMUTABLE"
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The item's position among its siblings, and the order the menu renders in. Changed with `:move`; sending it is an error.",
            "x-field-behavior": "IMMUTABLE",
            "x-sortable": true
          },
          "level": {
            "type": "integer",
            "format": "int64",
            "description": "How deep the item sits, counting the top level as 0. Server-generated; sending it is an error.",
            "x-field-behavior": "IMMUTABLE"
          },
          "html": {
            "type": "string",
            "description": "The markup a `RAW_HTML` item renders instead of a link \u2014 a language switcher, a badge, a call button.",
            "x-field-behavior": "OPTIONAL"
          },
          "target": {
            "type": "string",
            "description": "The link target, when the item should not open in place: `_blank` for a new tab.",
            "x-field-behavior": "OPTIONAL"
          },
          "view_id": {
            "type": "string",
            "description": "A view this item belongs to on its own. Usually empty \u2014 a shared item is translated through its `views` overlay instead.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the item is rendered in the menu.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "show_subcategories": {
            "type": "boolean",
            "description": "For a `BLOG_CATEGORY` item: whether the category's children are rendered as a submenu. Absent counts as on.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/menus/9c2d40f7e1ab/items/1b7e5a03c9d2",
            "id": "1b7e5a03c9d2",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "menu_id": "string",
            "title": "Our services",
            "type": "CMS_PAGE",
            "url": "string",
            "cms_page_id": "string",
            "blog_category_id": "string",
            "blog_author_id": "string",
            "blog_post_id": "string",
            "blog_tag_id": "string",
            "parent_id": "string",
            "path": "string",
            "sort_order": 0,
            "level": 0,
            "html": "string",
            "target": "string",
            "view_id": "string",
            "enabled": true,
            "show_subcategories": true
          }
        ]
      },
      "MenuItemCreate": {
        "type": "object",
        "description": "The `items` fields a client may set on create.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The text of the link, as the menu renders it.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Our services"
            ]
          },
          "type": {
            "type": "string",
            "description": "What the item points at, which decides which of the fields below is read: `TEXT` (a heading with no link), `URL`, `CMS_PAGE`, `RAW_HTML`, `BLOG`, `BLOG_CATEGORY`, `BLOG_AUTHOR`, `BLOG_POST`, `BLOG_TAG` or `FEEDBACK_FORM`.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "CMS_PAGE"
            ]
          },
          "url": {
            "type": "string",
            "description": "The address a `URL` item points at. Anything else \u2014 a page, a category, a post \u2014 is linked by its id below, so the URL follows the resource when its slug or its view changes.",
            "x-field-behavior": "OPTIONAL"
          },
          "cms_page_id": {
            "type": "string",
            "description": "The page a `CMS_PAGE` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_category_id": {
            "type": "string",
            "description": "The category a `BLOG_CATEGORY` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_author_id": {
            "type": "string",
            "description": "The author a `BLOG_AUTHOR` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_post_id": {
            "type": "string",
            "description": "The post a `BLOG_POST` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_tag_id": {
            "type": "string",
            "description": "The tag a `BLOG_TAG` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "parent_id": {
            "type": "string",
            "description": "The item this one nests under; empty at the top level. Settable on create and immutable afterwards \u2014 re-nesting is `:move`.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true
          },
          "path": {
            "type": "string",
            "description": "The item's position in the menu tree, as the ids of its ancestors and its own. Server-generated: sending it is an error rather than a no-op.",
            "x-field-behavior": "IMMUTABLE"
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The item's position among its siblings, and the order the menu renders in. Changed with `:move`; sending it is an error.",
            "x-field-behavior": "IMMUTABLE",
            "x-sortable": true
          },
          "level": {
            "type": "integer",
            "format": "int64",
            "description": "How deep the item sits, counting the top level as 0. Server-generated; sending it is an error.",
            "x-field-behavior": "IMMUTABLE"
          },
          "html": {
            "type": "string",
            "description": "The markup a `RAW_HTML` item renders instead of a link \u2014 a language switcher, a badge, a call button.",
            "x-field-behavior": "OPTIONAL"
          },
          "target": {
            "type": "string",
            "description": "The link target, when the item should not open in place: `_blank` for a new tab.",
            "x-field-behavior": "OPTIONAL"
          },
          "view_id": {
            "type": "string",
            "description": "A view this item belongs to on its own. Usually empty \u2014 a shared item is translated through its `views` overlay instead.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the item is rendered in the menu.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "show_subcategories": {
            "type": "boolean",
            "description": "For a `BLOG_CATEGORY` item: whether the category's children are rendered as a submenu. Absent counts as on.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "title",
          "type"
        ],
        "examples": [
          {
            "title": "Our services",
            "type": "CMS_PAGE"
          }
        ]
      },
      "MenuItemUpdate": {
        "type": "object",
        "description": "The `items` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "title": {
            "type": "string",
            "description": "The text of the link, as the menu renders it.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Our services"
            ]
          },
          "type": {
            "type": "string",
            "description": "What the item points at, which decides which of the fields below is read: `TEXT` (a heading with no link), `URL`, `CMS_PAGE`, `RAW_HTML`, `BLOG`, `BLOG_CATEGORY`, `BLOG_AUTHOR`, `BLOG_POST`, `BLOG_TAG` or `FEEDBACK_FORM`.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "examples": [
              "CMS_PAGE"
            ]
          },
          "url": {
            "type": "string",
            "description": "The address a `URL` item points at. Anything else \u2014 a page, a category, a post \u2014 is linked by its id below, so the URL follows the resource when its slug or its view changes.",
            "x-field-behavior": "OPTIONAL"
          },
          "cms_page_id": {
            "type": "string",
            "description": "The page a `CMS_PAGE` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_category_id": {
            "type": "string",
            "description": "The category a `BLOG_CATEGORY` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_author_id": {
            "type": "string",
            "description": "The author a `BLOG_AUTHOR` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_post_id": {
            "type": "string",
            "description": "The post a `BLOG_POST` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "blog_tag_id": {
            "type": "string",
            "description": "The tag a `BLOG_TAG` item points at.",
            "x-field-behavior": "OPTIONAL"
          },
          "html": {
            "type": "string",
            "description": "The markup a `RAW_HTML` item renders instead of a link \u2014 a language switcher, a badge, a call button.",
            "x-field-behavior": "OPTIONAL"
          },
          "target": {
            "type": "string",
            "description": "The link target, when the item should not open in place: `_blank` for a new tab.",
            "x-field-behavior": "OPTIONAL"
          },
          "view_id": {
            "type": "string",
            "description": "A view this item belongs to on its own. Usually empty \u2014 a shared item is translated through its `views` overlay instead.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the item is rendered in the menu.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "show_subcategories": {
            "type": "boolean",
            "description": "For a `BLOG_CATEGORY` item: whether the category's children are rendered as a submenu. Absent counts as on.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "title": "Our services",
            "type": "CMS_PAGE"
          }
        ]
      },
      "MenuItemView": {
        "type": "object",
        "description": "What one view says instead of the master menu item: its text, its URL, its raw markup and whether it is shown at all. What the item points at and where it sits in the menu are not overridable.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/menus/9c2d40f7e1ab/items/1b7e5a03c9d2/views/d48a2f6b0c73"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "d48a2f6b0c73"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "uid": {
            "type": "string",
            "description": "The overlay's own storage id, kept for clients that stored it before the overlay had a resource name.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "menu_item_id": {
            "type": "string",
            "description": "The menu item this overlay belongs to. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "view_id": {
            "type": "string",
            "description": "The view this overlay speaks for. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field not listed here falls back to the item.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "title"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's text for the link.",
            "x-field-behavior": "OPTIONAL"
          },
          "url": {
            "type": "string",
            "description": "This view's address for a `URL` item.",
            "x-field-behavior": "OPTIONAL"
          },
          "html": {
            "type": "string",
            "description": "This view's markup for a `RAW_HTML` item.",
            "x-field-behavior": "OPTIONAL"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether this view renders the item at all \u2014 the one way to hide a single link in one language.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/menus/9c2d40f7e1ab/items/1b7e5a03c9d2/views/d48a2f6b0c73",
            "id": "d48a2f6b0c73",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "uid": "string",
            "menu_item_id": "string",
            "view_id": "string",
            "overridden": [
              "title"
            ],
            "title": "string",
            "url": "string",
            "html": "string",
            "enabled": true
          }
        ]
      },
      "MenuItemViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field not listed here falls back to the item.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "title"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's text for the link.",
            "x-field-behavior": "OPTIONAL"
          },
          "url": {
            "type": "string",
            "description": "This view's address for a `URL` item.",
            "x-field-behavior": "OPTIONAL"
          },
          "html": {
            "type": "string",
            "description": "This view's markup for a `RAW_HTML` item.",
            "x-field-behavior": "OPTIONAL"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether this view renders the item at all \u2014 the one way to hide a single link in one language.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "title"
            ],
            "title": "string"
          }
        ]
      },
      "MenuItemViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "overridden": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the fields this view actually overrides. A field not listed here falls back to the item.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              [
                "title"
              ]
            ]
          },
          "title": {
            "type": "string",
            "description": "This view's text for the link.",
            "x-field-behavior": "OPTIONAL"
          },
          "url": {
            "type": "string",
            "description": "This view's address for a `URL` item.",
            "x-field-behavior": "OPTIONAL"
          },
          "html": {
            "type": "string",
            "description": "This view's markup for a `RAW_HTML` item.",
            "x-field-behavior": "OPTIONAL"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether this view renders the item at all \u2014 the one way to hide a single link in one language.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "overridden": [
              "title"
            ],
            "title": "string"
          }
        ]
      },
      "Menu": {
        "type": "object",
        "description": "A named navigation menu of the website \u2014 the container its items hang off. A theme points at one by `code`; the links themselves are the `items` collection under it.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/menus/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The menu's label in the admin. It is not rendered on the site \u2014 a menu is its items.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Main menu"
            ]
          },
          "code": {
            "type": "string",
            "description": "The handle a theme refers to this menu by \u2014 which is how a theme picks its main menu without knowing an id.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "main"
            ]
          },
          "view_id": {
            "type": "string",
            "description": "A view this menu belongs to on its own, for a menu that exists in one view only. Usually empty: a shared menu is translated through its items' overlays instead.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the menu is rendered.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/menus/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Main menu",
            "code": "main",
            "view_id": "string",
            "is_active": true
          }
        ]
      },
      "MenuCreate": {
        "type": "object",
        "description": "The `menus` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The menu's label in the admin. It is not rendered on the site \u2014 a menu is its items.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Main menu"
            ]
          },
          "code": {
            "type": "string",
            "description": "The handle a theme refers to this menu by \u2014 which is how a theme picks its main menu without knowing an id.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "main"
            ]
          },
          "view_id": {
            "type": "string",
            "description": "A view this menu belongs to on its own, for a menu that exists in one view only. Usually empty: a shared menu is translated through its items' overlays instead.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the menu is rendered.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "required": [
          "display_name",
          "code"
        ],
        "examples": [
          {
            "display_name": "Main menu",
            "code": "main"
          }
        ]
      },
      "MenuUpdate": {
        "type": "object",
        "description": "The `menus` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The menu's label in the admin. It is not rendered on the site \u2014 a menu is its items.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Main menu"
            ]
          },
          "code": {
            "type": "string",
            "description": "The handle a theme refers to this menu by \u2014 which is how a theme picks its main menu without knowing an id.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "main"
            ]
          },
          "view_id": {
            "type": "string",
            "description": "A view this menu belongs to on its own, for a menu that exists in one view only. Usually empty: a shared menu is translated through its items' overlays instead.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the menu is rendered.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "x-sortable": true
          }
        },
        "examples": [
          {
            "display_name": "Main menu",
            "code": "main"
          }
        ]
      },
      "Project": {
        "type": "object",
        "description": "A grouping of websites inside one account \u2014 the parent every website is created under. One project is enough for a single site; an agency keeps one per client.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/projects/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "account_id": {
            "type": "string",
            "description": "The account this project belongs to. The URL already fixes it, so a write cannot move a project between accounts.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          },
          "display_name": {
            "type": "string",
            "description": "The project's label, unique inside its account.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Client sites"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the project is in use. Nothing filters on it for you \u2014 it is the tenant's own flag for retiring a project without deleting it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "icon_color": {
            "type": "string",
            "description": "The colour, `#rrggbb`, that the admin tints this project's badge with when it lists several projects side by side. Leave it unset and the admin derives a stable colour from the id \u2014 set it only to override that choice, and send `null` to go back to the derived one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "#0ea5e9"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "accounts/6f3b1c8e2a4d/projects/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "account_id": "string",
            "display_name": "Client sites",
            "is_active": true,
            "icon_color": "#0ea5e9"
          }
        ]
      },
      "ProjectCreate": {
        "type": "object",
        "description": "The `projects` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The project's label, unique inside its account.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Client sites"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the project is in use. Nothing filters on it for you \u2014 it is the tenant's own flag for retiring a project without deleting it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "icon_color": {
            "type": "string",
            "description": "The colour, `#rrggbb`, that the admin tints this project's badge with when it lists several projects side by side. Leave it unset and the admin derives a stable colour from the id \u2014 set it only to override that choice, and send `null` to go back to the derived one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "#0ea5e9"
            ]
          }
        },
        "required": [
          "display_name",
          "is_active"
        ],
        "examples": [
          {
            "display_name": "Client sites",
            "is_active": true
          }
        ]
      },
      "ProjectUpdate": {
        "type": "object",
        "description": "The `projects` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The project's label, unique inside its account.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Client sites"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the project is in use. Nothing filters on it for you \u2014 it is the tenant's own flag for retiring a project without deleting it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "icon_color": {
            "type": "string",
            "description": "The colour, `#rrggbb`, that the admin tints this project's badge with when it lists several projects side by side. Leave it unset and the admin derives a stable colour from the id \u2014 set it only to override that choice, and send `null` to go back to the derived one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "#0ea5e9"
            ]
          }
        },
        "examples": [
          {
            "display_name": "Client sites",
            "is_active": true
          }
        ]
      },
      "Theme": {
        "type": "object",
        "description": "How the site looks and what furniture it renders: the CSS-variable map, plus the logo, the favicon, the main menu and the footer block the layout pulls in. A website can hold several themes; which one it renders is the `appearance.theme.default_theme` setting, and that setting is view-overridable \u2014 so one language can wear a different theme, and swap its navigation and footer with it.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/themes/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The theme's label in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Winter 2026"
            ]
          },
          "code": {
            "type": "string",
            "description": "The theme's handle, unique on the website.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "winter-2026"
            ]
          },
          "styles": {
            "description": "The CSS custom properties the site renders with, as a flat object keyed by variable name. A variable this API has never heard of survives a round trip untouched, so a client may set one the renderer gained after this document was generated.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              {
                "--brand-color": "#0b5cff",
                "--radius": "8px"
              }
            ]
          },
          "main_menu_id": {
            "type": "string",
            "description": "The `menus` resource rendered as the site's main navigation.",
            "x-field-behavior": "OPTIONAL"
          },
          "footer_block_id": {
            "type": "string",
            "description": "The `cms_blocks` resource rendered in the footer.",
            "x-field-behavior": "OPTIONAL"
          },
          "logo_media_id": {
            "type": "string",
            "description": "The `media` resource used as the site's logo.",
            "x-field-behavior": "OPTIONAL"
          },
          "favicon_media_id": {
            "type": "string",
            "description": "The `media` resource used as the site's favicon.",
            "x-field-behavior": "OPTIONAL"
          },
          "custom_css": {
            "type": "string",
            "description": "A stylesheet appended after the theme's own, for the rules the variables cannot express.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/themes/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "display_name": "Winter 2026",
            "code": "winter-2026",
            "styles": {
              "--brand-color": "#0b5cff",
              "--radius": "8px"
            },
            "main_menu_id": "string",
            "footer_block_id": "string",
            "logo_media_id": "string",
            "favicon_media_id": "string",
            "custom_css": "string"
          }
        ]
      },
      "ThemeCreate": {
        "type": "object",
        "description": "The `themes` fields a client may set on create.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The theme's label in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Winter 2026"
            ]
          },
          "code": {
            "type": "string",
            "description": "The theme's handle, unique on the website.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "winter-2026"
            ]
          },
          "styles": {
            "description": "The CSS custom properties the site renders with, as a flat object keyed by variable name. A variable this API has never heard of survives a round trip untouched, so a client may set one the renderer gained after this document was generated.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              {
                "--brand-color": "#0b5cff",
                "--radius": "8px"
              }
            ]
          },
          "main_menu_id": {
            "type": "string",
            "description": "The `menus` resource rendered as the site's main navigation.",
            "x-field-behavior": "OPTIONAL"
          },
          "footer_block_id": {
            "type": "string",
            "description": "The `cms_blocks` resource rendered in the footer.",
            "x-field-behavior": "OPTIONAL"
          },
          "logo_media_id": {
            "type": "string",
            "description": "The `media` resource used as the site's logo.",
            "x-field-behavior": "OPTIONAL"
          },
          "favicon_media_id": {
            "type": "string",
            "description": "The `media` resource used as the site's favicon.",
            "x-field-behavior": "OPTIONAL"
          },
          "custom_css": {
            "type": "string",
            "description": "A stylesheet appended after the theme's own, for the rules the variables cannot express.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "required": [
          "display_name",
          "code",
          "styles"
        ],
        "examples": [
          {
            "display_name": "Winter 2026",
            "code": "winter-2026",
            "styles": {
              "--brand-color": "#0b5cff",
              "--radius": "8px"
            }
          }
        ]
      },
      "ThemeUpdate": {
        "type": "object",
        "description": "The `themes` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The theme's label in the admin.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Winter 2026"
            ]
          },
          "code": {
            "type": "string",
            "description": "The theme's handle, unique on the website.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "winter-2026"
            ]
          },
          "styles": {
            "description": "The CSS custom properties the site renders with, as a flat object keyed by variable name. A variable this API has never heard of survives a round trip untouched, so a client may set one the renderer gained after this document was generated.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              {
                "--brand-color": "#0b5cff",
                "--radius": "8px"
              }
            ]
          },
          "main_menu_id": {
            "type": "string",
            "description": "The `menus` resource rendered as the site's main navigation.",
            "x-field-behavior": "OPTIONAL"
          },
          "footer_block_id": {
            "type": "string",
            "description": "The `cms_blocks` resource rendered in the footer.",
            "x-field-behavior": "OPTIONAL"
          },
          "logo_media_id": {
            "type": "string",
            "description": "The `media` resource used as the site's logo.",
            "x-field-behavior": "OPTIONAL"
          },
          "favicon_media_id": {
            "type": "string",
            "description": "The `media` resource used as the site's favicon.",
            "x-field-behavior": "OPTIONAL"
          },
          "custom_css": {
            "type": "string",
            "description": "A stylesheet appended after the theme's own, for the rules the variables cannot express.",
            "x-field-behavior": "OPTIONAL"
          }
        },
        "examples": [
          {
            "display_name": "Winter 2026",
            "code": "winter-2026",
            "styles": {
              "--brand-color": "#0b5cff",
              "--radius": "8px"
            }
          }
        ]
      },
      "Profile": {
        "type": "object",
        "description": "The signed-in user's own record. It is a singleton (\u00a79): there is no id in the URL because the bearer token already names whose profile this is, so there is no way to read anyone else's. Read it, patch it, or close the account with `profile:delete_account` \u2014 `DELETE` on a singleton is not a thing.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "profile"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "profile"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "email": {
            "type": "string",
            "description": "The address the account signs in with. Changing it changes the sign-in identity.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "ada@example.com"
            ]
          },
          "firstname": {
            "type": "string",
            "description": "The user's given name, as the admin greets them.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Ada"
            ]
          },
          "lastname": {
            "type": "string",
            "description": "The user's family name, shown beside the given one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Lovelace"
            ]
          },
          "interface_locale": {
            "type": "string",
            "description": "The language the admin interface is shown to this user in. It has nothing to do with the languages the websites are published in \u2014 those are views.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "en"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the account is usable. It is not settable here \u2014 closing an account is `profile:delete_account`.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY"
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "profile",
            "id": "profile",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "email": "ada@example.com",
            "firstname": "Ada",
            "lastname": "Lovelace",
            "interface_locale": "en",
            "is_active": true
          }
        ]
      },
      "ProfileCreate": {
        "type": "object",
        "description": "The `profile` fields a client may set on create.",
        "properties": {
          "email": {
            "type": "string",
            "description": "The address the account signs in with. Changing it changes the sign-in identity.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "ada@example.com"
            ]
          },
          "firstname": {
            "type": "string",
            "description": "The user's given name, as the admin greets them.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Ada"
            ]
          },
          "lastname": {
            "type": "string",
            "description": "The user's family name, shown beside the given one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Lovelace"
            ]
          },
          "interface_locale": {
            "type": "string",
            "description": "The language the admin interface is shown to this user in. It has nothing to do with the languages the websites are published in \u2014 those are views.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "en"
            ]
          },
          "password": {
            "type": "string",
            "description": "A new password. Write-only: it is applied and never echoed back, and setting it needs `current_password` in the same body.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY"
          },
          "current_password": {
            "type": "string",
            "description": "The password in force right now, proving the session belongs to whoever is changing it. Write-only, and only meaningful alongside `password`.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY"
          }
        },
        "required": [
          "email"
        ],
        "examples": [
          {
            "email": "ada@example.com"
          }
        ]
      },
      "ProfileUpdate": {
        "type": "object",
        "description": "The `profile` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "email": {
            "type": "string",
            "description": "The address the account signs in with. Changing it changes the sign-in identity.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "ada@example.com"
            ]
          },
          "firstname": {
            "type": "string",
            "description": "The user's given name, as the admin greets them.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Ada"
            ]
          },
          "lastname": {
            "type": "string",
            "description": "The user's family name, shown beside the given one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Lovelace"
            ]
          },
          "interface_locale": {
            "type": "string",
            "description": "The language the admin interface is shown to this user in. It has nothing to do with the languages the websites are published in \u2014 those are views.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "en"
            ]
          },
          "password": {
            "type": "string",
            "description": "A new password. Write-only: it is applied and never echoed back, and setting it needs `current_password` in the same body.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY"
          },
          "current_password": {
            "type": "string",
            "description": "The password in force right now, proving the session belongs to whoever is changing it. Write-only, and only meaningful alongside `password`.",
            "writeOnly": true,
            "x-field-behavior": "INPUT_ONLY"
          }
        },
        "examples": [
          {
            "email": "ada@example.com"
          }
        ]
      },
      "View": {
        "type": "object",
        "description": "One presentation of the website \u2014 in practice, one language: its locale, its URL prefix, its place in the switcher and its fallback. A view is not a copy of the site: content stays one resource and carries a per-view overlay, and settings can be overridden per view. Everything a visitor sees is decided by the view their URL resolved to.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/views/9c2d40f7e1ab"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "code": {
            "type": "string",
            "description": "The view's handle, unique on the website. Content overlays and view-scoped settings are addressed by the view, so this is the name a person uses for it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "de"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label the visitor-facing language switcher shows \u2014 the language's own name (\"Deutsch\"), not a translation of it.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Deutsch"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the view is served. Switching it off takes one language off the site without deleting anything written for it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "locale": {
            "type": "string",
            "description": "The language this view renders in, as a BCP 47 tag. It picks the interface translations and the date and number formats.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "de-DE"
            ]
          },
          "path_prefix": {
            "type": "string",
            "description": "The first URL segment that routes to this view (`/de/...`). Empty means this view answers at the bare root \u2014 at most one view per website may.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "de"
            ]
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The view's position in the language switcher.",
            "x-field-behavior": "OPTIONAL"
          },
          "fallback_view_id": {
            "type": "string",
            "description": "The view to fall back to when this one has nothing of its own to show for a page.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/views/9c2d40f7e1ab",
            "id": "9c2d40f7e1ab",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "code": "de",
            "display_name": "Deutsch",
            "is_active": true,
            "locale": "de-DE",
            "path_prefix": "de",
            "sort_order": 0,
            "fallback_view_id": "string"
          }
        ]
      },
      "ViewCreate": {
        "type": "object",
        "description": "The `views` fields a client may set on create.",
        "properties": {
          "code": {
            "type": "string",
            "description": "The view's handle, unique on the website. Content overlays and view-scoped settings are addressed by the view, so this is the name a person uses for it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "de"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label the visitor-facing language switcher shows \u2014 the language's own name (\"Deutsch\"), not a translation of it.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Deutsch"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the view is served. Switching it off takes one language off the site without deleting anything written for it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "locale": {
            "type": "string",
            "description": "The language this view renders in, as a BCP 47 tag. It picks the interface translations and the date and number formats.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "de-DE"
            ]
          },
          "path_prefix": {
            "type": "string",
            "description": "The first URL segment that routes to this view (`/de/...`). Empty means this view answers at the bare root \u2014 at most one view per website may.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "de"
            ]
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The view's position in the language switcher.",
            "x-field-behavior": "OPTIONAL"
          },
          "fallback_view_id": {
            "type": "string",
            "description": "The view to fall back to when this one has nothing of its own to show for a page.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "required": [
          "code",
          "is_active"
        ],
        "examples": [
          {
            "code": "de",
            "is_active": true
          }
        ]
      },
      "ViewUpdate": {
        "type": "object",
        "description": "The `views` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "code": {
            "type": "string",
            "description": "The view's handle, unique on the website. Content overlays and view-scoped settings are addressed by the view, so this is the name a person uses for it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "de"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The label the visitor-facing language switcher shows \u2014 the language's own name (\"Deutsch\"), not a translation of it.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "Deutsch"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the view is served. Switching it off takes one language off the site without deleting anything written for it.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "locale": {
            "type": "string",
            "description": "The language this view renders in, as a BCP 47 tag. It picks the interface translations and the date and number formats.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "de-DE"
            ]
          },
          "path_prefix": {
            "type": "string",
            "description": "The first URL segment that routes to this view (`/de/...`). Empty means this view answers at the bare root \u2014 at most one view per website may.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true,
            "examples": [
              "de"
            ]
          },
          "sort_order": {
            "type": "integer",
            "format": "int64",
            "description": "The view's position in the language switcher.",
            "x-field-behavior": "OPTIONAL"
          },
          "fallback_view_id": {
            "type": "string",
            "description": "The view to fall back to when this one has nothing of its own to show for a page.",
            "x-field-behavior": "OPTIONAL",
            "x-filterable": true
          }
        },
        "examples": [
          {
            "code": "de",
            "is_active": true
          }
        ]
      },
      "SettingDescriptor": {
        "type": "object",
        "description": "The registry of setting paths the platform knows about, and which of them may be overridden per view. It is read-only and it is not website-scoped: the paths come from the platform and its features, not from a tenant, which is exactly why a client cannot invent one by writing to `settings`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "setting_descriptors/general.info.site_name"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "general.info.site_name"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "path": {
            "type": "string",
            "description": "The dotted path this entry describes \u2014 the id a setting is written under.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "general.info.site_name"
            ]
          },
          "view_overridable": {
            "type": "boolean",
            "description": "Whether this path may be given a different value per view. `?filter=view_overridable = true` is the list a per-view settings screen should offer.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "setting_descriptors/general.info.site_name",
            "id": "general.info.site_name",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "path": "general.info.site_name",
            "view_overridable": true
          }
        ]
      },
      "SettingDescriptorCreate": {
        "type": "object",
        "description": "The `setting_descriptors` fields a client may set on create.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "SettingDescriptorUpdate": {
        "type": "object",
        "description": "The `setting_descriptors` fields to merge. Fields absent from the body are left untouched.",
        "properties": {},
        "examples": [
          {}
        ]
      },
      "ViewSetting": {
        "type": "object",
        "description": "One setting overridden for one view. Same shape as the website-wide collection and the same upsert rule \u2014 `PATCH` on a path never written for this view creates the override \u2014 with two differences: the path must be one `setting_descriptors` marks `view_overridable`, and deleting the resource removes the override rather than the setting \u2014 the view goes back to the website-wide value.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/views/9c2d40f7e1ab/settings/general.info.site_name"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "general.info.site_name"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "path": {
            "type": "string",
            "description": "The setting's dotted path, which is also its id. Only a path whose `setting_descriptors` entry says `view_overridable` may be written here.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "general.info.site_name"
            ]
          },
          "view_id": {
            "type": "string",
            "description": "The view this override belongs to. Fixed by the URL.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          },
          "value": {
            "description": "The value this view uses instead of the website-wide one. Any JSON, whichever shape the setting is defined to hold.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Northwind Laden"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/views/9c2d40f7e1ab/settings/general.info.site_name",
            "id": "general.info.site_name",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "path": "general.info.site_name",
            "view_id": "string",
            "value": "Northwind Laden"
          }
        ]
      },
      "ViewSettingCreate": {
        "type": "object",
        "description": "The `settings` fields a client may set on create.",
        "properties": {
          "value": {
            "description": "The value this view uses instead of the website-wide one. Any JSON, whichever shape the setting is defined to hold.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Northwind Laden"
            ]
          }
        },
        "required": [
          "value"
        ],
        "examples": [
          {
            "value": "Northwind Laden"
          }
        ]
      },
      "ViewSettingUpdate": {
        "type": "object",
        "description": "The `settings` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "value": {
            "description": "The value this view uses instead of the website-wide one. Any JSON, whichever shape the setting is defined to hold.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Northwind Laden"
            ]
          }
        },
        "examples": [
          {
            "value": "Northwind Laden"
          }
        ]
      },
      "Website": {
        "type": "object",
        "description": "The unit the platform publishes: one website is one site, with its own pages, blog, media, menus, themes, views and settings hanging off it. Creating one starts provisioning and answers with an Operation to poll (\u00a717) \u2014 the resource exists immediately, but it is not servable until that Operation is `done`. Everything else in this API is addressed under `websites/{website}`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "6f3b1c8e2a4d"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "parent": {
            "type": "string",
            "description": "The resource name of the project this website belongs to, `accounts/{account}/projects/{project}` \u2014 the link upward that the website's own one-segment name no longer carries.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "accounts/6f3b1c8e2a4d/projects/9c2d40f7e1ab"
            ]
          },
          "project_id": {
            "type": "string",
            "description": "The last segment of `parent`. Settable on create, immutable afterwards: a website does not move between projects.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "code": {
            "type": "string",
            "description": "The website's short slug, and the label the platform hostname is built from. Immutable \u2014 changing it would move a live site's URL.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "northwind"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The website's label in the admin. Free text, and unrelated to the hostname \u2014 that is `code`.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Northwind Store"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the website is live. The list on this surface returns only active websites \u2014 an inactive one is still reachable by name, it is just not browsable.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "provisioning_status": {
            "type": "string",
            "description": "How far provisioning has got: `PENDING`, `READY` or `FAILED`. It is here so a list can show a site that is still coming up \u2014 to wait for one, poll the Operation that Create named (\u00a717).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "examples": [
              "READY"
            ]
          },
          "type": {
            "type": "string",
            "description": "The kind of site this was provisioned as, which chose its seeded content. Set at signup and not changed afterwards.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          },
          "icon_color": {
            "type": "string",
            "description": "The colour, `#rrggbb`, that the admin tints this website's badge with when it lists several sites side by side. Leave it unset and the admin derives a stable colour from the id \u2014 set it only to override that choice, and send `null` to go back to the derived one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "#7c3aed"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d",
            "id": "6f3b1c8e2a4d",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "parent": "accounts/6f3b1c8e2a4d/projects/9c2d40f7e1ab",
            "project_id": "9c2d40f7e1ab",
            "code": "northwind",
            "display_name": "Northwind Store",
            "is_active": true,
            "provisioning_status": "READY",
            "type": "string",
            "icon_color": "#7c3aed"
          }
        ]
      },
      "WebsiteCreate": {
        "type": "object",
        "description": "The `websites` fields a client may set on create.",
        "properties": {
          "project_id": {
            "type": "string",
            "description": "The last segment of `parent`. Settable on create, immutable afterwards: a website does not move between projects.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "examples": [
              "9c2d40f7e1ab"
            ]
          },
          "code": {
            "type": "string",
            "description": "The website's short slug, and the label the platform hostname is built from. Immutable \u2014 changing it would move a live site's URL.",
            "x-field-behavior": "IMMUTABLE",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "northwind"
            ]
          },
          "display_name": {
            "type": "string",
            "description": "The website's label in the admin. Free text, and unrelated to the hostname \u2014 that is `code`.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Northwind Store"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the website is live. The list on this surface returns only active websites \u2014 an inactive one is still reachable by name, it is just not browsable.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "icon_color": {
            "type": "string",
            "description": "The colour, `#rrggbb`, that the admin tints this website's badge with when it lists several sites side by side. Leave it unset and the admin derives a stable colour from the id \u2014 set it only to override that choice, and send `null` to go back to the derived one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "#7c3aed"
            ]
          }
        },
        "required": [
          "display_name",
          "is_active"
        ],
        "examples": [
          {
            "display_name": "Northwind Store",
            "is_active": true
          }
        ]
      },
      "WebsiteUpdate": {
        "type": "object",
        "description": "The `websites` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "The website's label in the admin. Free text, and unrelated to the hostname \u2014 that is `code`.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "Northwind Store"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the website is live. The list on this surface returns only active websites \u2014 an inactive one is still reachable by name, it is just not browsable.",
            "x-field-behavior": "REQUIRED",
            "x-filterable": true
          },
          "icon_color": {
            "type": "string",
            "description": "The colour, `#rrggbb`, that the admin tints this website's badge with when it lists several sites side by side. Leave it unset and the admin derives a stable colour from the id \u2014 set it only to override that choice, and send `null` to go back to the derived one.",
            "x-field-behavior": "OPTIONAL",
            "examples": [
              "#7c3aed"
            ]
          }
        },
        "examples": [
          {
            "display_name": "Northwind Store",
            "is_active": true
          }
        ]
      },
      "Setting": {
        "type": "object",
        "description": "One website-wide setting, addressed by its dotted path. Two things about this collection are worth knowing before you write to it: the id is the path, and there is no Create \u2014 the platform decides which paths exist, so `PATCH` on a path never written before creates it. `:batch_update` writes many at once, which is what a settings screen should send instead of a burst of single writes.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The resource name (\u00a75) \u2014 the identity of this resource, and the path that addresses it: `websites/{website}/cms_pages/{cms_page}`. It is the handle to store, not a human label.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "websites/6f3b1c8e2a4d/settings/general.info.site_name"
            ]
          },
          "id": {
            "type": "string",
            "description": "The last segment of `name` on its own, for a client that needs to build a child URL. Unique inside its parent, never across the platform.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "general.info.site_name"
            ]
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource was created (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "When the resource last changed (RFC 3339, UTC).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "2026-01-15T09:30:00Z"
            ]
          },
          "etag": {
            "type": "string",
            "description": "Version of the persisted state. Send it back in `If-Match` on Update or Delete and the write is rejected with ABORTED if anyone else changed the resource meanwhile (\u00a714).",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "examples": [
              "\"3f8a1b2c4d5e\""
            ]
          },
          "path": {
            "type": "string",
            "description": "The setting's dotted path, which is also its id \u2014 `general.info.site_name`, `appearance.theme.default_theme`. Which paths exist is decided by the platform, so a write cannot invent one and cannot move one.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true,
            "x-sortable": true,
            "examples": [
              "general.info.site_name"
            ]
          },
          "view_id": {
            "type": "string",
            "description": "Empty on this collection: these are the website-wide values. A value overridden for one view is a resource of `websites/{website}/views/{view}/settings`, and carries that view there.",
            "readOnly": true,
            "x-field-behavior": "OUTPUT_ONLY",
            "x-filterable": true
          },
          "value": {
            "description": "The setting's value \u2014 any JSON: a string, a number, a boolean, an object or an array, whichever the setting is defined to hold.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Northwind Store"
            ]
          }
        },
        "required": [
          "name",
          "id"
        ],
        "examples": [
          {
            "name": "websites/6f3b1c8e2a4d/settings/general.info.site_name",
            "id": "general.info.site_name",
            "create_time": "2026-01-15T09:30:00Z",
            "update_time": "2026-01-15T09:30:00Z",
            "etag": "\"3f8a1b2c4d5e\"",
            "path": "general.info.site_name",
            "view_id": "string",
            "value": "Northwind Store"
          }
        ]
      },
      "SettingCreate": {
        "type": "object",
        "description": "The `settings` fields a client may set on create.",
        "properties": {
          "value": {
            "description": "The setting's value \u2014 any JSON: a string, a number, a boolean, an object or an array, whichever the setting is defined to hold.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Northwind Store"
            ]
          }
        },
        "required": [
          "value"
        ],
        "examples": [
          {
            "value": "Northwind Store"
          }
        ]
      },
      "SettingUpdate": {
        "type": "object",
        "description": "The `settings` fields to merge. Fields absent from the body are left untouched.",
        "properties": {
          "value": {
            "description": "The setting's value \u2014 any JSON: a string, a number, a boolean, an object or an array, whichever the setting is defined to hold.",
            "x-field-behavior": "REQUIRED",
            "examples": [
              "Northwind Store"
            ]
          }
        },
        "examples": [
          {
            "value": "Northwind Store"
          }
        ]
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "\u00a719: `Authorization: Bearer <jwt>`. No API keys, no tokens in query strings, no session cookies."
      }
    }
  },
  "x-public-surface": "/tenant-api",
  "x-generator": {
    "source": "cmake/tools/extract_openapi_endpoints.py",
    "total_operations": 267,
    "total_paths": 146,
    "warnings": []
  }
}
