{
  "openapi": "3.1.0",
  "info": {
    "title": "Rink site runtime API",
    "version": "1.7.0",
    "description": "The HTTP contract behind the `rink.*` browser SDK. These `/_rink/*` routes are called from browser code on an internal Rink site through `/rink.js`.\n\nCalls are same-origin: identity comes from the viewer's SeenThis Google SSO session cookie and tenancy from the site host (`{site}.rink.staging-aws.seenthis.io` or an approved internal alias). A site can never choose another site's data scope. Unsafe methods must carry a same-origin `Origin` header.\n\nThe API is not available on public hosts: they serve static content or bounded shares only.\n\nPrefer the SDK in site code; it adds realtime, polling and the error contract (`error.message`, `error.status`). Handler errors use `{ \"error\": string }`."
  },
  "servers": [
    {
      "url": "https://{site}.rink.staging-aws.seenthis.io",
      "variables": {
        "site": {
          "default": "your-site",
          "description": "Rink site slug"
        }
      }
    }
  ],
  "security": [
    {
      "seenthisSso": []
    }
  ],
  "tags": [
    {
      "name": "Platform",
      "description": "rink.platform: live environment contract."
    },
    {
      "name": "Identity",
      "description": "rink.identity: the current SSO viewer."
    },
    {
      "name": "Directory",
      "description": "rink.directory: safe colleague profiles."
    },
    {
      "name": "Data",
      "description": "rink.db: schemaless JSON documents with server-enforced mutation policies."
    },
    {
      "name": "SQL",
      "description": "rink.sql: deploy-reviewed named SQLite statements."
    },
    {
      "name": "Files",
      "description": "rink.files: per-site binary storage."
    },
    {
      "name": "Email",
      "description": "rink.email: internal email to SeenThis recipients."
    },
    {
      "name": "Forms",
      "description": "rink.forms: named form submissions."
    },
    {
      "name": "Schedules",
      "description": "rink.schedule / rink.cron: scheduled jobs."
    },
    {
      "name": "Workflows",
      "description": "rink.workflow: if-this-then-that automations."
    },
    {
      "name": "BigQuery",
      "description": "rink.bq: read-only shared DWH data from datasets granted to the site."
    },
    {
      "name": "AI",
      "description": "rink.ai: text, image and video generation with server-held keys."
    },
    {
      "name": "GitHub",
      "description": "rink.github: read-only issue snapshots."
    },
    {
      "name": "HTTP",
      "description": "rink.http: outbound HTTPS with server-side Rink Secrets."
    },
    {
      "name": "Location",
      "description": "rink.location: offices and approximate location."
    },
    {
      "name": "Weather",
      "description": "rink.weather: current conditions and forecasts."
    },
    {
      "name": "Shares",
      "description": "rink.shares: bounded public file and URL shares."
    },
    {
      "name": "Snapshots",
      "description": "rink.snapshots: reviewed data snapshots for viewers and invited guests."
    },
    {
      "name": "Realtime",
      "description": "rink.live: site-scoped WebSocket pub/sub."
    }
  ],
  "paths": {
    "/_rink/platform": {
      "get": {
        "operationId": "getPlatformInfo",
        "tags": [
          "Platform"
        ],
        "summary": "Returns the live release, API version, SDK path and capability manifest.",
        "description": "Feature detection for the Rink environment actually serving the site. Not cached. The handler itself does not resolve the site or viewer; on site hosts it sits behind SeenThis SSO like every other route.",
        "x-rink-sdk": "rink.platform.info",
        "responses": {
          "200": {
            "description": "Platform info.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlatformInfo"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "Identity"
        ],
        "summary": "Reads the current viewer. No app-specific login flow is needed.",
        "description": "SSO identity enriched with safe professional fields from the SeenThis directory. Never derive authorization from name, department or team.",
        "x-rink-sdk": "rink.identity.me",
        "responses": {
          "200": {
            "description": "The current viewer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/directory": {
      "get": {
        "operationId": "listDirectory",
        "tags": [
          "Directory"
        ],
        "summary": "Lists active colleagues available in Rink's cached directory.",
        "x-rink-sdk": "rink.directory.list",
        "responses": {
          "200": {
            "description": "Colleague profiles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "people": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Person"
                      }
                    }
                  },
                  "required": [
                    "people"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/directory/{email}": {
      "get": {
        "operationId": "lookupDirectoryPerson",
        "tags": [
          "Directory"
        ],
        "summary": "Looks up one colleague by exact email address.",
        "x-rink-sdk": "rink.directory.lookup",
        "parameters": [
          {
            "name": "email",
            "in": "path",
            "required": true,
            "description": "Colleague email (URL-encoded).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The person, or null when there is no matching active profile.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "person": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Person"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "person"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/location/offices": {
      "get": {
        "operationId": "listOffices",
        "tags": [
          "Location"
        ],
        "summary": "Lists SeenThis offices and their location metadata.",
        "x-rink-sdk": "rink.location.offices",
        "responses": {
          "200": {
            "description": "Offices.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "offices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Office"
                      }
                    },
                    "source": {
                      "type": "string",
                      "description": "Office list source URL."
                    }
                  },
                  "required": [
                    "offices",
                    "source"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/location/approximate": {
      "get": {
        "operationId": "getApproximateLocation",
        "tags": [
          "Location"
        ],
        "summary": "Returns coarse location inferred from edge headers or the viewer IP without prompting.",
        "x-rink-sdk": "rink.location.approximate",
        "responses": {
          "200": {
            "description": "Approximate location, or null.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "location": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/ApproximateLocation"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "location"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/location/nearest-office": {
      "get": {
        "operationId": "getNearestOffice",
        "tags": [
          "Location"
        ],
        "summary": "Finds the closest SeenThis office to coordinates.",
        "description": "The SDK's nearestOffice() obtains coordinates (browser geolocation when omitted) and adds `location` client-side.",
        "x-rink-sdk": "rink.location.nearestOffice",
        "parameters": [
          {
            "name": "latitude",
            "in": "query",
            "required": true,
            "description": "Latitude, -90..90.",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "longitude",
            "in": "query",
            "required": true,
            "description": "Longitude, -180..180.",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Nearest office.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "office": {
                      "$ref": "#/components/schemas/Office"
                    },
                    "distanceKm": {
                      "type": "number"
                    },
                    "source": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "office",
                    "distanceKm",
                    "source"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). latitude and longitude are missing or not valid coordinates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/weather/current": {
      "post": {
        "operationId": "getCurrentWeather",
        "tags": [
          "Weather"
        ],
        "summary": "Reads current conditions for coordinates or a SeenThis office.",
        "x-rink-sdk": "rink.weather.current",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WeatherInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current weather.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrentWeather"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid location, unknown office, or the upstream weather request failed or timed out (8 s).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/weather/forecast": {
      "post": {
        "operationId": "getWeatherForecast",
        "tags": [
          "Weather"
        ],
        "summary": "Reads a daily forecast.",
        "x-rink-sdk": "rink.weather.forecast",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WeatherInput"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "days": {
                        "type": "integer",
                        "default": 5,
                        "description": "Clamped to 1-14."
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Daily forecast.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeatherForecast"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid location, unknown office, or the upstream weather request failed or timed out (8 s).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/github/issue": {
      "post": {
        "operationId": "getGitHubIssue",
        "tags": [
          "GitHub"
        ],
        "summary": "Fetches metadata for one allowed GitHub issue URL.",
        "description": "Read-only. Organization and repository allowlists are enforced server-side. Snapshots are cached for 60 seconds; each site/viewer may cause 10 uncached lookups per minute.",
        "x-rink-sdk": "rink.github.getIssue",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "https://github.com/{owner}/{repo}/issues/{number}"
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Issue snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "issue": {
                      "$ref": "#/components/schemas/GitHubIssue"
                    }
                  },
                  "required": [
                    "issue"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Missing or invalid issue URL, or a pull request URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The repository is not allowed for Rink sites.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). The issue was not found or is not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "GitHub issue lookup rate limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "GitHub lookup failed or returned invalid data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "GitHub issue lookup is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/http/fetch": {
      "post": {
        "operationId": "httpFetch",
        "tags": [
          "HTTP"
        ],
        "summary": "Makes one outbound HTTPS request with Rink Secrets filled in server-side.",
        "description": "`{{secret:NAME}}` (site secret) and `{{secret:me.NAME}}` (the viewer's personal secret) are substituted in the URL query, header values and a text body; at least one is required, and never in the scheme, host, port or path. Each secret is only sent to its allowed hosts over HTTPS port 443, also after redirects; site secrets follow their use policy (`viewers` or `editors`) and personal secrets only serve their owner. The destination is resolved once, must be a public address and the connection is pinned to it. Hop-by-hop headers and `cookie` are stripped. Limits: request body 1 MB, response body 5 MB, 15 s, 60 requests/minute per viewer and 600 per site. The host allowlist is the security boundary (an allowed host receives the credential). As defense in depth, compressed responses are decoded and occurrences of each used secret (raw, URL-encoded, JSON-escaped, base64/base64url, hex) are replaced by `[redacted]`; secrets with responseAccess `status-only` return only the status and safe headers. Upstream non-2xx statuses are returned in `status` with HTTP 200.",
        "x-rink-sdk": "rink.http.fetch",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Absolute https:// URL. Placeholders only in the query."
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "GET",
                      "HEAD",
                      "POST",
                      "PUT",
                      "PATCH",
                      "DELETE"
                    ],
                    "default": "GET"
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "Header values may contain placeholders."
                  },
                  "body": {
                    "type": "string",
                    "description": "Request body; text bodies may contain placeholders. Not allowed for GET/HEAD."
                  },
                  "bodyEncoding": {
                    "type": "string",
                    "enum": [
                      "text",
                      "base64"
                    ],
                    "default": "text"
                  },
                  "followRedirects": {
                    "type": "boolean",
                    "default": false,
                    "description": "Follow up to 3 redirects, re-validating every hop."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upstream response, redacted, or status only for status-only secrets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpFetchResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid URL, method, headers or body; malformed or unknown placeholder; no placeholder; placeholder outside the query, header values or body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Use policy, personal-secret ownership, allowed host or port refused the request; destination is private or internal; admin view-as.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request body over 1 MB or upstream response over 5 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rink.http.fetch rate limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Upstream connection failed, timed out or redirected too often.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Secrets are not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/forms/{form}": {
      "post": {
        "operationId": "submitForm",
        "tags": [
          "Forms"
        ],
        "summary": "Creates one submission and triggers enabled form.submit workflows.",
        "description": "Stored as a Doc in `form_{name}` through that collection's create policy. Workflow failures do not roll back a valid submission. The SDK returns only `submission`.",
        "x-rink-sdk": "rink.forms.submit",
        "parameters": [
          {
            "name": "form",
            "in": "path",
            "required": true,
            "description": "Form name: 1-59 letters, digits, `_` or `-`; stored in collection `form_{name}`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,58}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "description": "Submitted values: any JSON value."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Submission created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "submission": {
                      "$ref": "#/components/schemas/FormSubmission"
                    },
                    "workflowRuns": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WorkflowRun"
                      }
                    },
                    "workflowError": {
                      "type": "string",
                      "description": "Present when triggering workflows failed."
                    }
                  },
                  "required": [
                    "submission",
                    "workflowRuns"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid form name or submission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Denied by the collection's mutation policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Document exceeds 256 KB or the site reached 50,000 documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listFormSubmissions",
        "tags": [
          "Forms"
        ],
        "summary": "Lists submissions for one form.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.forms.list",
        "parameters": [
          {
            "name": "form",
            "in": "path",
            "required": true,
            "description": "Form name: 1-59 letters, digits, `_` or `-`; stored in collection `form_{name}`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,58}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum documents to return. Defaults to 100, capped at 200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Order by creation time. Anything other than `asc` means `desc`.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Submissions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "submissions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FormSubmission"
                      }
                    }
                  },
                  "required": [
                    "submissions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid form name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). The viewer is not the site owner or an editor (`Only the owner and members can list form submissions`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/forms/{form}/{id}": {
      "get": {
        "operationId": "getFormSubmission",
        "tags": [
          "Forms"
        ],
        "summary": "Reads one submission.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.forms.get",
        "parameters": [
          {
            "name": "form",
            "in": "path",
            "required": true,
            "description": "Form name: 1-59 letters, digits, `_` or `-`; stored in collection `form_{name}`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,58}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Document UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The submission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "submission": {
                      "$ref": "#/components/schemas/FormSubmission"
                    }
                  },
                  "required": [
                    "submission"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid form name or id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). The viewer is not the site owner or an editor (`Only the owner and members can read form submissions`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such submission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteFormSubmission",
        "tags": [
          "Forms"
        ],
        "summary": "Deletes one submission.",
        "description": "Site owner and editors, and the form collection's delete policy.",
        "x-rink-sdk": "rink.forms.remove",
        "parameters": [
          {
            "name": "form",
            "in": "path",
            "required": true,
            "description": "Form name: 1-59 letters, digits, `_` or `-`; stored in collection `form_{name}`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,58}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Document UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid form name or id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can delete form submissions`). Or denied by the delete policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such submission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/db-policy/{collection}": {
      "get": {
        "operationId": "getCollectionPermissions",
        "tags": [
          "Data"
        ],
        "summary": "Asks the server which mutations the current viewer may perform.",
        "description": "Supply `id` to include that document's created_by owner rule; omit it for collection-wide permissions. Use this to render controls, but still handle 403. Response is `Cache-Control: private, no-store`.",
        "x-rink-sdk": "rink.db.collection(name).permissions",
        "parameters": [
          {
            "name": "collection",
            "in": "path",
            "required": true,
            "description": "Collection name: 1-64 letters, digits, `_` or `-`; the first character must be alphanumeric.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Optional document UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Effective permissions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "permissions": {
                      "$ref": "#/components/schemas/DataPermissions"
                    }
                  },
                  "required": [
                    "permissions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid collection name, or empty/invalid document id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/db/{collection}": {
      "get": {
        "operationId": "listDocuments",
        "tags": [
          "Data"
        ],
        "summary": "Lists documents ordered by creation time.",
        "description": "Read access follows site visibility; mutation policies do not hide records. No filtering or cursor pagination.",
        "x-rink-sdk": "rink.db.collection(name).list",
        "parameters": [
          {
            "name": "collection",
            "in": "path",
            "required": true,
            "description": "Collection name: 1-64 letters, digits, `_` or `-`; the first character must be alphanumeric.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum documents to return. Defaults to 100, capped at 200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Order by creation time. Anything other than `asc` means `desc`.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "docs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Doc"
                      }
                    }
                  },
                  "required": [
                    "docs"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid collection name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createDocument",
        "tags": [
          "Data"
        ],
        "summary": "Stores one JSON-compatible value and records the caller as its immutable creator.",
        "description": "Enforced by the collection's create policy. Max 256 KB serialized; max 50,000 documents per site. An empty body is stored as `{}`.",
        "x-rink-sdk": "rink.db.collection(name).create",
        "parameters": [
          {
            "name": "collection",
            "in": "path",
            "required": true,
            "description": "Collection name: 1-64 letters, digits, `_` or `-`; the first character must be alphanumeric.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "description": "Any JSON value."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "doc": {
                      "$ref": "#/components/schemas/Doc"
                    }
                  },
                  "required": [
                    "doc"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid collection name or document id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Denied by the collection's mutation policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Document exceeds 256 KB or the site reached 50,000 documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/db/{collection}/{id}": {
      "get": {
        "operationId": "getDocument",
        "tags": [
          "Data"
        ],
        "summary": "Reads one document by UUID.",
        "x-rink-sdk": "rink.db.collection(name).get",
        "parameters": [
          {
            "name": "collection",
            "in": "path",
            "required": true,
            "description": "Collection name: 1-64 letters, digits, `_` or `-`; the first character must be alphanumeric.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Document UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "doc": {
                      "$ref": "#/components/schemas/Doc"
                    }
                  },
                  "required": [
                    "doc"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid collection name or document id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateDocument",
        "tags": [
          "Data"
        ],
        "summary": "Replaces a document's complete data value. Audit envelope fields remain server-owned.",
        "description": "Updates replace the complete data value; they do not merge. Enforced by the update policy, including the document owner rule.",
        "x-rink-sdk": "rink.db.collection(name).update",
        "parameters": [
          {
            "name": "collection",
            "in": "path",
            "required": true,
            "description": "Collection name: 1-64 letters, digits, `_` or `-`; the first character must be alphanumeric.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Document UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "description": "The complete replacement JSON value."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "doc": {
                      "$ref": "#/components/schemas/Doc"
                    }
                  },
                  "required": [
                    "doc"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid collection name or document id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Denied by the collection's mutation policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Document exceeds 256 KB or the site reached 50,000 documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteDocument",
        "tags": [
          "Data"
        ],
        "summary": "Permanently deletes one document.",
        "description": "Enforced by the delete policy, including the document owner rule.",
        "x-rink-sdk": "rink.db.collection(name).remove",
        "parameters": [
          {
            "name": "collection",
            "in": "path",
            "required": true,
            "description": "Collection name: 1-64 letters, digits, `_` or `-`; the first character must be alphanumeric.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Document UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid collection name or document id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Denied by the collection's delete policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/sql/execute": {
      "post": {
        "operationId": "executeSqlStatement",
        "tags": [
          "SQL"
        ],
        "summary": "Executes one named statement from the active deploy's rink.sql.json.",
        "description": "Raw browser SQL is never accepted. Results are capped at 1,000 rows and 1 MB; two-second execution deadline. Reserved bindings `_rink_actor_email`, `_rink_site_id` and `_rink_now` are injected by Rink. The SDK's all()/run() return `result`; first()/raw() return `result.results`.",
        "x-rink-sdk": "rink.sql.statement(name).bind(params).all|first|run|raw",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SqlRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Statement result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "result": {
                      "$ref": "#/components/schemas/SqlResult"
                    },
                    "generation": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "result",
                    "generation"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid request, bindings or SQL execution error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The statement's access policy denies the viewer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No active deploy, no rink.sql manifest/database, or unknown statement.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "Execution exceeded the deadline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The transaction changes too much data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "SQL executor busy or snapshot/journal unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/sql/batch": {
      "post": {
        "operationId": "executeSqlBatch",
        "tags": [
          "SQL"
        ],
        "summary": "Runs up to 25 named statements sequentially in one SQLite transaction when any item writes.",
        "description": "Every item must independently pass its statement policy; one denial or SQL error aborts the complete batch.",
        "x-rink-sdk": "rink.sql.batch",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "statements": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/SqlRequest"
                    },
                    "minItems": 1,
                    "maxItems": 25
                  }
                },
                "required": [
                  "statements"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Results in input order.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SqlResult"
                      }
                    },
                    "generation": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "results",
                    "generation"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid request, bindings or SQL execution error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The statement's access policy denies the viewer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No active deploy, no rink.sql manifest/database, or unknown statement.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "Execution exceeded the deadline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The transaction changes too much data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "SQL executor busy or snapshot/journal unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/email": {
      "post": {
        "operationId": "sendEmail",
        "tags": [
          "Email"
        ],
        "summary": "Sends one email and attributes usage to the current site and viewer.",
        "description": "SeenThis recipients only; 20 sends per minute per viewer.",
        "x-rink-sdk": "rink.email.send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). `to` is not a @seenthis address, or subject and text/html are missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Email rate limit (20/min).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The mail service rejected the message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/cron": {
      "get": {
        "operationId": "listScheduledJobs",
        "tags": [
          "Schedules"
        ],
        "summary": "Lists scheduled jobs and their latest execution state.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.schedule.list",
        "responses": {
          "200": {
            "description": "Jobs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CronJob"
                      }
                    }
                  },
                  "required": [
                    "jobs"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). The viewer is not the site owner or an editor (`Only the owner and members can manage jobs`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createScheduledJob",
        "tags": [
          "Schedules"
        ],
        "summary": "Creates a cron job. rink.cron is an exact alias of rink.schedule.",
        "description": "Site owner and editors only. Maximum 10 jobs per site.",
        "x-rink-sdk": "rink.schedule.add",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CronJobInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Job created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    }
                  },
                  "required": [
                    "id"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid cron expression or action, unsafe webhook destination, or job limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can add jobs`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/cron/{id}": {
      "delete": {
        "operationId": "deleteScheduledJob",
        "tags": [
          "Schedules"
        ],
        "summary": "Permanently deletes one scheduled job.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.schedule.cancel",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Job id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can remove jobs`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such job.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "tags": [
          "Workflows"
        ],
        "summary": "Lists up to 20 workflow definitions.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.workflow.list",
        "responses": {
          "200": {
            "description": "Workflows.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workflows": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Workflow"
                      }
                    }
                  },
                  "required": [
                    "workflows"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). The viewer is not the site owner or an editor (`Only the owner and members can manage workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Creates a workflow definition and its schedule job when applicable.",
        "description": "Site owner and editors only. One trigger and 1-10 ordered steps.",
        "x-rink-sdk": "rink.workflow.create",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkflowInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Workflow created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workflow": {
                      "$ref": "#/components/schemas/Workflow"
                    }
                  },
                  "required": [
                    "workflow"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid trigger or steps, or schedule job creation failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can create workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Data quota exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/workflows/{id}": {
      "get": {
        "operationId": "getWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Reads one workflow by ID.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.workflow.get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Workflow id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workflow": {
                      "$ref": "#/components/schemas/Workflow"
                    }
                  },
                  "required": [
                    "workflow"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). The viewer is not the site owner or an editor (`Only the owner and members can manage workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Deletes the workflow and its backing schedule job.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.workflow.remove",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Workflow id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can manage workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/workflows/{id}/run": {
      "post": {
        "operationId": "runWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Runs a workflow immediately with a manual event, even when automatic triggering is disabled.",
        "description": "Site owner and editors only. Steps execute sequentially; an ordinary step failure is recorded in the run (status `error`) rather than failing the request.",
        "x-rink-sdk": "rink.workflow.run",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Workflow id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run record.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "run": {
                      "$ref": "#/components/schemas/WorkflowRun"
                    }
                  },
                  "required": [
                    "run"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). The workflow does not exist (`No such workflow`) or the run could not be recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can run workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/workflows/{id}/runs": {
      "get": {
        "operationId": "listWorkflowRuns",
        "tags": [
          "Workflows"
        ],
        "summary": "Lists recent run records for one workflow.",
        "description": "Site owner and editors only. Up to 100 matching runs, newest first.",
        "x-rink-sdk": "rink.workflow.runs",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Workflow id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Run records.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WorkflowRun"
                      }
                    }
                  },
                  "required": [
                    "runs"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). The viewer is not the site owner or an editor (`Only the owner and members can read workflow runs`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/workflows/{id}/enable": {
      "post": {
        "operationId": "enableWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Enables automatic triggering and its backing schedule job.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.workflow.enable",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Workflow id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Updated workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workflow": {
                      "$ref": "#/components/schemas/Workflow"
                    }
                  },
                  "required": [
                    "workflow"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). The backing schedule job could not be created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can manage workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/workflows/{id}/disable": {
      "post": {
        "operationId": "disableWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Disables automatic triggering and its backing schedule job.",
        "description": "Site owner and editors only.",
        "x-rink-sdk": "rink.workflow.disable",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Workflow id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Updated workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workflow": {
                      "$ref": "#/components/schemas/Workflow"
                    }
                  },
                  "required": [
                    "workflow"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). The viewer is not the site owner or an editor (`Only the owner and members can manage workflows`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such workflow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/files": {
      "get": {
        "operationId": "listFiles",
        "tags": [
          "Files"
        ],
        "summary": "Lists stored file metadata, newest first.",
        "description": "Up to 1,000 files.",
        "x-rink-sdk": "rink.files.list",
        "responses": {
          "200": {
            "description": "Files.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "files": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FileMeta"
                      }
                    }
                  },
                  "required": [
                    "files"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "uploadFile",
        "tags": [
          "Files"
        ],
        "summary": "Uploads a File or Blob as raw bytes.",
        "description": "Send the raw bytes with `Content-Type: application/octet-stream`; name and MIME type go in the query string. Maximum 100 MB per file and 500 files per site. Empty files are rejected.",
        "x-rink-sdk": "rink.files.upload",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "File name. Defaults to `file`; sanitized and capped at 200 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "MIME type stored for the file. Defaults to `application/octet-stream`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "contentMediaType": "application/octet-stream"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Stored file.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "file": {
                      "$ref": "#/components/schemas/FileMeta"
                    }
                  },
                  "required": [
                    "file"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Empty file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "File too large (100 MB) or too many files (500 per site).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/files/{id}/meta": {
      "get": {
        "operationId": "getFileMeta",
        "tags": [
          "Files"
        ],
        "summary": "Reads metadata for one file without downloading its bytes.",
        "x-rink-sdk": "rink.files.get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "File UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "file": {
                      "$ref": "#/components/schemas/FileMeta"
                    }
                  },
                  "required": [
                    "file"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/files/{id}": {
      "get": {
        "operationId": "downloadFile",
        "tags": [
          "Files"
        ],
        "summary": "Serves a file's bytes on the site's own origin.",
        "description": "Returned with the stored Content-Type, `Content-Disposition: inline` and `Cache-Control: private, max-age=3600`. This is the URL `rink.files.url(id)` builds (usable as img/video src). Not servable on public hosts.",
        "x-rink-sdk": "rink.files.url",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "File UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file bytes.",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/octet-stream"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteFile",
        "tags": [
          "Files"
        ],
        "summary": "Deletes file metadata and its stored bytes.",
        "description": "Any viewer who can open the site. There is currently no per-file owner policy.",
        "x-rink-sdk": "rink.files.remove",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "File UUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/bq/query": {
      "post": {
        "operationId": "bigQueryQuery",
        "tags": [
          "BigQuery"
        ],
        "summary": "Runs a read-only query on the site's granted DWH datasets, or fetches the next page.",
        "description": "Rink dry-runs every query first: it must be a single SELECT and every referenced table must belong to an active grant of this site. The estimate is checked against the per-query, per-site and per-viewer daily caps; the job runs with maximumBytesBilled, a 60 s timeout and labels rink_site / rink_user (hashed) / rink_source. Results are shared site data and cached per site for `cacheTtl` seconds (default 300, max 86,400). Pages hold at most 10,000 rows / 10 MB.",
        "x-rink-sdk": "rink.bq.query / rink.bq.nextPage",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BqQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rows and typed schema.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BqQueryResult"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid SQL, parameters or options, or BigQuery rejected the query.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`). `as: \"me\"`: your Google connection was revoked or has expired, or Google rejected it. Reconnect at `connectUrl` (body `code: \"reconnect\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The dry-run estimate exceeds the per-query maximum (maximumBytesBilled, default 100 GB). The body carries `estimateBytes` and `caps`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Not a read-only SELECT, a table or routine outside the site's active grants, no grants, or the site's bq_policy is `editors`. With `as: \"me\"`: Google denied your own access (the body's `denied` names the table, dataset or project), or you are not an owner or editor of the site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Unknown or expired pageToken.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "The BigQuery job exceeded 60 seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`as: \"me\"`: you have not connected your Google account. The body carries `connectUrl` (`code: \"not_connected\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "The site's or viewer's daily BigQuery budget would be exceeded. The body carries `estimateBytes`, `caps` and today's usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "BigQuery request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "BigQuery (or, for `as: \"me\"`, connected Google accounts) is not configured on this Rink.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/bq/estimate": {
      "post": {
        "operationId": "bigQueryEstimate",
        "tags": [
          "BigQuery"
        ],
        "summary": "Dry-runs a query: validation, bytes scanned and estimated cost, without charge.",
        "x-rink-sdk": "rink.bq.estimate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sql": {
                    "type": "string"
                  },
                  "params": {
                    "$ref": "#/components/schemas/BqParams"
                  },
                  "types": {
                    "$ref": "#/components/schemas/BqTypes"
                  },
                  "as": {
                    "type": "string",
                    "enum": [
                      "me"
                    ],
                    "description": "Run with your own connected Google account (My account → Connected accounts at /account) instead of the site's shared service account: Google IAM of the signed-in user decides what can be read, so no site dataset grant is needed. Owners and editors of the site only, on internal hosts, never cached by Rink. The same SELECT-only dry run, maximumBytesBilled reservation, site and per-user daily caps and labels (plus `rink_identity: user`) apply."
                  },
                  "location": {
                    "type": "string",
                    "description": "See BqQueryRequest.location."
                  }
                },
                "required": [
                  "sql"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimate and cap headroom.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BqEstimate"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid SQL, parameters or options, or BigQuery rejected the query.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`). `as: \"me\"`: your Google connection was revoked or has expired, or Google rejected it. Reconnect at `connectUrl` (body `code: \"reconnect\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The dry-run estimate exceeds the per-query maximum (maximumBytesBilled, default 100 GB). The body carries `estimateBytes` and `caps`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Not a read-only SELECT, a table or routine outside the site's active grants, no grants, or the site's bq_policy is `editors`. With `as: \"me\"`: Google denied your own access (the body's `denied` names the table, dataset or project), or you are not an owner or editor of the site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "The BigQuery job exceeded 60 seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`as: \"me\"`: you have not connected your Google account. The body carries `connectUrl` (`code: \"not_connected\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "The site's or viewer's daily BigQuery budget would be exceeded. The body carries `estimateBytes`, `caps` and today's usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "BigQuery request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "BigQuery (or, for `as: \"me\"`, connected Google accounts) is not configured on this Rink.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/snapshots/{name}.json": {
      "get": {
        "operationId": "getSnapshot",
        "tags": [
          "Snapshots"
        ],
        "summary": "Returns the current version of a guest data snapshot declared in rink.snapshots.json.",
        "description": "Fixed, reviewed outputs refreshed on a schedule without a deploy. On the internal site host the active deploy must declare `name` with `viewers` in its audience. The same path also answers on the site's public guest host (`{site}.<external domain>` or an approved vanity host), outside this SSO contract: there it requires a valid guest invite cookie and a definition with `guests` in the approved public deploy, and every other request gets the visitor 404 (see docs/public-shares.md, Guest data snapshots). Query parameters are rejected; every viewer and guest receives the same bytes. Responses are `private, no-store` with `Surrogate-Control: no-store` and carry `X-Rink-Snapshot-Version` and `X-Rink-Snapshot-Generated-At`. Reads are logged as `snapshot_read` usage events (one per reader and snapshot per 10 minutes). A BigQuery-sourced version is withheld while any dataset it read is no longer granted to the site.",
        "x-rink-sdk": "rink.snapshots.get",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "Snapshot name: 1-64 lowercase letters, digits, `_` or `-`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The snapshot JSON (at most 10,000 rows / 5 MB).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string",
                      "description": "Immutable version id, also in `X-Rink-Snapshot-Version`."
                    },
                    "generatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "bq",
                        "collection"
                      ]
                    },
                    "schema": {
                      "anyOf": [
                        {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {},
                            "additionalProperties": true
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "rows": {
                      "type": "array",
                      "items": {}
                    },
                    "rowCount": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "name",
                    "version",
                    "generatedAt",
                    "source",
                    "schema",
                    "rows",
                    "rowCount"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Query parameters are not accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such snapshot for viewers, it has no successful version yet, its data source is no longer granted, or the site is offline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/bq/datasets": {
      "get": {
        "operationId": "bigQueryDatasets",
        "tags": [
          "BigQuery"
        ],
        "summary": "Lists the DWH datasets actively granted to this site.",
        "description": "Only this site's grants are visible. Any viewer who can open the site.",
        "x-rink-sdk": "rink.bq.datasets",
        "responses": {
          "200": {
            "description": "Granted datasets.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "datasets": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BqDataset"
                      }
                    },
                    "policy": {
                      "type": "string",
                      "enum": [
                        "viewers",
                        "editors"
                      ]
                    },
                    "caps": {
                      "$ref": "#/components/schemas/BqCaps"
                    }
                  },
                  "required": [
                    "datasets",
                    "policy",
                    "caps"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "BigQuery is not configured on this Rink.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/bq/tables": {
      "get": {
        "operationId": "bigQueryTables",
        "tags": [
          "BigQuery"
        ],
        "summary": "Lists tables and views in a granted dataset with size, partitioning, clustering and curated notes.",
        "description": "From INFORMATION_SCHEMA; cached for an hour per dataset. Datasets not granted to this site return 404.",
        "x-rink-sdk": "rink.bq.tables",
        "parameters": [
          {
            "name": "dataset",
            "in": "query",
            "required": true,
            "description": "Granted dataset, e.g. `seenthis-insights.dwh` or `dwh`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tables.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dataset": {
                      "type": "string"
                    },
                    "notes": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tables": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BqTable"
                      }
                    }
                  },
                  "required": [
                    "dataset",
                    "tables"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid SQL, parameters or options, or BigQuery rejected the query.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`). `as: \"me\"`: your Google connection was revoked or has expired, or Google rejected it. Reconnect at `connectUrl` (body `code: \"reconnect\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The dry-run estimate exceeds the per-query maximum (maximumBytesBilled, default 100 GB). The body carries `estimateBytes` and `caps`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Not a read-only SELECT, a table or routine outside the site's active grants, no grants, or the site's bq_policy is `editors`. With `as: \"me\"`: Google denied your own access (the body's `denied` names the table, dataset or project), or you are not an owner or editor of the site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). The dataset is not granted to this site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "The BigQuery job exceeded 60 seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`as: \"me\"`: you have not connected your Google account. The body carries `connectUrl` (`code: \"not_connected\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "The site's or viewer's daily BigQuery budget would be exceeded. The body carries `estimateBytes`, `caps` and today's usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "BigQuery request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "BigQuery (or, for `as: \"me\"`, connected Google accounts) is not configured on this Rink.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/bq/schema": {
      "get": {
        "operationId": "bigQuerySchema",
        "tags": [
          "BigQuery"
        ],
        "summary": "Reads the columns of one table or view in a granted dataset.",
        "description": "From INFORMATION_SCHEMA.COLUMN_FIELD_PATHS (types, modes, descriptions, nested fields) plus curated notes; cached for an hour.",
        "x-rink-sdk": "rink.bq.schema",
        "parameters": [
          {
            "name": "table",
            "in": "query",
            "required": true,
            "description": "`dataset.table` or `project.dataset.table`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schema.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BqTableSchema"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid SQL, parameters or options, or BigQuery rejected the query.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`). `as: \"me\"`: your Google connection was revoked or has expired, or Google rejected it. Reconnect at `connectUrl` (body `code: \"reconnect\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The dry-run estimate exceeds the per-query maximum (maximumBytesBilled, default 100 GB). The body carries `estimateBytes` and `caps`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Not a read-only SELECT, a table or routine outside the site's active grants, no grants, or the site's bq_policy is `editors`. With `as: \"me\"`: Google denied your own access (the body's `denied` names the table, dataset or project), or you are not an owner or editor of the site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Unknown table, or its dataset is not granted to this site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "The BigQuery job exceeded 60 seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`as: \"me\"`: you have not connected your Google account. The body carries `connectUrl` (`code: \"not_connected\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "The site's or viewer's daily BigQuery budget would be exceeded. The body carries `estimateBytes`, `caps` and today's usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "BigQuery request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "BigQuery (or, for `as: \"me\"`, connected Google accounts) is not configured on this Rink.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/bq/sample": {
      "get": {
        "operationId": "bigQuerySample",
        "tags": [
          "BigQuery"
        ],
        "summary": "Returns a few example rows from a table using TABLESAMPLE.",
        "description": "Tables only (views would scan everything behind them). Runs through rink.bq.query, so it is validated, capped, labelled and counts against the daily budgets.",
        "x-rink-sdk": "rink.bq.sample",
        "parameters": [
          {
            "name": "table",
            "in": "query",
            "required": true,
            "description": "`dataset.table` or `project.dataset.table`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows (default 20, max 100).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sample rows.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/BqQueryResult"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "table": {
                          "type": "string"
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "tablesample",
                            "limit"
                          ]
                        }
                      },
                      "required": [
                        "table",
                        "method"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid SQL, parameters or options, or BigQuery rejected the query.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`). `as: \"me\"`: your Google connection was revoked or has expired, or Google rejected it. Reconnect at `connectUrl` (body `code: \"reconnect\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The dry-run estimate exceeds the per-query maximum (maximumBytesBilled, default 100 GB). The body carries `estimateBytes` and `caps`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Not a read-only SELECT, a table or routine outside the site's active grants, no grants, or the site's bq_policy is `editors`. With `as: \"me\"`: Google denied your own access (the body's `denied` names the table, dataset or project), or you are not an owner or editor of the site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Unknown table, or its dataset is not granted to this site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "408": {
            "description": "The BigQuery job exceeded 60 seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`as: \"me\"`: you have not connected your Google account. The body carries `connectUrl` (`code: \"not_connected\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "The site's or viewer's daily BigQuery budget would be exceeded. The body carries `estimateBytes`, `caps` and today's usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "BigQuery request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "BigQuery (or, for `as: \"me\"`, connected Google accounts) is not configured on this Rink.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/ai/chat": {
      "post": {
        "operationId": "aiChat",
        "tags": [
          "AI"
        ],
        "summary": "Generates text with Claude by default or an allowed Gemini model.",
        "description": "Draws from the viewer's personal AI credit. Default output 1,024 tokens, max 16,384. Images work with Claude models only. The SDK unwraps and returns only `content`. Request bodies are limited to 16 MB.",
        "x-rink-sdk": "rink.ai.chat",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated text.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid messages/options, unknown model, or images sent to a Gemini model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The viewer is out of AI credit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit: 30 AI requests per minute per viewer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Provider request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The provider is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/ai/image": {
      "post": {
        "operationId": "aiImage",
        "tags": [
          "AI"
        ],
        "summary": "Generates an image and stores it automatically in rink.files.",
        "description": "Gemini (Nano Banana) image generation. Default model gemini-2.5-flash-image; allowed: gemini-2.5-flash-image, gemini-3-pro-image, nano-banana-pro-preview, nano-banana, nano-banana-2, nano-banana-pro. The SDK returns only `file`.",
        "x-rink-sdk": "rink.ai.image",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateMediaRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Stored image.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "file": {
                      "$ref": "#/components/schemas/FileMeta"
                    },
                    "model": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "file",
                    "model"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). prompt is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The viewer is out of AI credit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit: 30 AI requests per minute per viewer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Provider request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The provider is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/ai/video": {
      "post": {
        "operationId": "aiVideoStart",
        "tags": [
          "AI"
        ],
        "summary": "Starts a Veo video generation job.",
        "description": "Long-running: poll `GET /_rink/ai/video/{id}`. Default model veo-3.1-generate-preview; allowed: veo-3.1-generate-preview, veo-3.1-fast-generate-preview, veo-3.0-generate-001, veo, veo-3.1, veo-3.1-fast. Billed up front. The SDK's rink.ai.video() starts and polls (every 5 s, up to 120 polls).",
        "x-rink-sdk": "rink.ai.video",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateMediaRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "const": "pending"
                    }
                  },
                  "required": [
                    "jobId",
                    "status"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). prompt is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The viewer is out of AI credit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit: 30 AI requests per minute per viewer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Provider request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The provider is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/ai/video/{id}": {
      "get": {
        "operationId": "aiVideoStatus",
        "tags": [
          "AI"
        ],
        "summary": "Polls a video job; on completion the video is stored in rink.files once.",
        "description": "Transient provider polling failures return `pending`.",
        "x-rink-sdk": "rink.ai.video",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Video job id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoJobStatus"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). No such job.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/shares": {
      "get": {
        "operationId": "listShares",
        "tags": [
          "Shares"
        ],
        "summary": "Lists shares the viewer may see, with effective permissions.",
        "description": "Responses are `Cache-Control: no-store`.",
        "x-rink-sdk": "rink.shares.list",
        "responses": {
          "200": {
            "description": "Shares.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "shares": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Share"
                      }
                    },
                    "permissions": {
                      "$ref": "#/components/schemas/SharePermissions"
                    }
                  },
                  "required": [
                    "shares",
                    "permissions"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Site disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createShare",
        "tags": [
          "Shares"
        ],
        "summary": "Creates a public file or URL share.",
        "description": "Choose exactly one of `fileId` or `destination`. Published immediately. Limit 500 shares per site. Body limit 8 KB.",
        "x-rink-sdk": "rink.shares.create",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ShareCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created share.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Share"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share request (schema validation).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Site disabled, or the action is not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Share not found or not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: slug already exists, share revoked/unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Share or file limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Password service busy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/shares/policy": {
      "get": {
        "operationId": "getSharePolicy",
        "tags": [
          "Shares"
        ],
        "summary": "Reads whether sharing is enabled and the viewer's share permissions.",
        "x-rink-sdk": "rink.shares.policy",
        "responses": {
          "200": {
            "description": "Share policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharePolicy"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Site disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "configureShares",
        "tags": [
          "Shares"
        ],
        "summary": "Enables sharing and sets the app-admin allowlist.",
        "description": "Site owner and editors only. Initial configuration requires a site that has never served public static content.",
        "x-rink-sdk": "rink.shares.configure",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SharePolicyInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The stored policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharePolicyInput"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share request (schema validation).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Site disabled, or site editor access required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Sharing requires a site that has never served public static content.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/shares/{id}": {
      "get": {
        "operationId": "getShare",
        "tags": [
          "Shares"
        ],
        "summary": "Reads one share.",
        "x-rink-sdk": "rink.shares.get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Share id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The share.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Share"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Site disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Share not found or not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateShare",
        "tags": [
          "Shares"
        ],
        "summary": "Updates title, slug, expiry or password.",
        "description": "Creators, site editors and configured app admins only. Body limit 8 KB.",
        "x-rink-sdk": "rink.shares.update",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Share id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ShareUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated share.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Share"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share request (schema validation).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Site disabled, or the action is not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Share not found or not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: slug already exists, share revoked/unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Share or file limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Password service busy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/shares/{id}/revoke": {
      "post": {
        "operationId": "revokeShare",
        "tags": [
          "Shares"
        ],
        "summary": "Revokes a share. Idempotent for already-revoked shares.",
        "x-rink-sdk": "rink.shares.revoke",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Share id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked share.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Share"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share request (schema validation).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Site disabled, or the action is not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Share not found or not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: slug already exists, share revoked/unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Share or file limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Password service busy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/shares/{id}/submit": {
      "post": {
        "operationId": "submitShare",
        "tags": [
          "Shares"
        ],
        "summary": "Publishes a legacy draft share (compatibility; new shares publish on create).",
        "x-rink-sdk": "rink.shares.submit",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Share id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Published.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "queued": {
                      "type": "boolean",
                      "const": true
                    },
                    "published": {
                      "type": "boolean",
                      "const": true
                    },
                    "reviewDeployId": {
                      "type": "null"
                    }
                  },
                  "required": [
                    "queued",
                    "published",
                    "reviewDeployId"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share request (schema validation).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Cookie-authenticated unsafe request without a same-origin `Origin` header (`Cross-origin cookie-authenticated request denied`). Site disabled, or the action is not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Share not found or not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: slug already exists, share revoked/unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Share or file limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Password service busy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/shares/{id}/stats": {
      "get": {
        "operationId": "getShareStats",
        "tags": [
          "Shares"
        ],
        "summary": "Reads 90-day delivery counters for a share.",
        "x-rink-sdk": "rink.shares.stats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Share id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShareStats"
                }
              }
            }
          },
          "400": {
            "description": "The request host is not an internal Rink site host (`rink.* APIs are only available on a site host`). Invalid share id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No authenticated SeenThis viewer (`Unauthorized`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The viewer cannot open this site (`You don't have access to this site`). Site disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The site does not exist (`No such site`). Share not found or not accessible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/_rink/ws": {
      "get": {
        "operationId": "openRealtimeSocket",
        "tags": [
          "Realtime"
        ],
        "summary": "Opens the site-scoped realtime WebSocket (rink.live).",
        "description": "HTTP GET with `Upgrade: websocket`. One shared socket per page; the SDK reconnects after 1.5 s and resubscribes.\n\nAuth and tenancy are checked after the upgrade: an unauthorized viewer or non-site host gets close code 1008 `unauthorized`. On success the server sends `{\"type\":\"ready\"}`.\n\nClient messages (JSON): `{type:'subscribe'|'unsubscribe', channel}` and `{type:'publish', channel, data}`. Channel names match `^[a-zA-Z0-9][a-zA-Z0-9:_-]{0,64}$`; `db:*` channels cannot be published by clients.\n\nServer messages: `{type:'message', channel, data}`. `db:{collection}` carries `{event:'create'|'update', doc}` or `{event:'delete', id}`; `sql` carries `{event:'commit', generation, statements}`; oversized payloads arrive as `{_refetch:true}`.\n\nLimits: 50 messages/second and 50 subscribed channels per connection; 256 KB max payload. Realtime is ephemeral.",
        "x-rink-sdk": "rink.live.channel",
        "parameters": [
          {
            "name": "Upgrade",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "const": "websocket"
            }
          }
        ],
        "responses": {
          "101": {
            "description": "Switching Protocols: WebSocket established."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "seenthisSso": {
        "type": "apiKey",
        "in": "cookie",
        "name": "_st_auth_identity",
        "description": "SeenThis SSO session cookie, set by the SeenThis Google login. Sent automatically by the browser on the site origin."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message."
          }
        },
        "required": [
          "error"
        ],
        "description": "Error body used by every `/_rink/*` handler. The SDK rejects with `error.message` = this text and `error.status` = the HTTP status."
      },
      "Ok": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        },
        "required": [
          "ok"
        ]
      },
      "Manager": {
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "email",
          "name"
        ]
      },
      "Person": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name."
          },
          "slack": {
            "type": [
              "string",
              "null"
            ],
            "description": "Slack handle."
          },
          "jobTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "department": {
            "type": [
              "string",
              "null"
            ]
          },
          "team": {
            "type": [
              "string",
              "null"
            ],
            "description": "Verified Team field from HiBob. Never synthesize it from department."
          },
          "site": {
            "type": [
              "string",
              "null"
            ],
            "description": "Office/site the person belongs to."
          },
          "manager": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Manager"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "email",
          "name",
          "slack",
          "jobTitle",
          "department",
          "team",
          "site",
          "manager"
        ],
        "description": "Safe professional colleague profile. All fields except email are nullable."
      },
      "Me": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "SSO viewer email."
          },
          "user": {
            "type": "string",
            "description": "SSO viewer user name."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name."
          },
          "slack": {
            "type": [
              "string",
              "null"
            ],
            "description": "Slack handle."
          },
          "jobTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "department": {
            "type": [
              "string",
              "null"
            ]
          },
          "team": {
            "type": [
              "string",
              "null"
            ],
            "description": "Verified Team field from HiBob. Never synthesize it from department."
          },
          "site": {
            "type": [
              "string",
              "null"
            ],
            "description": "Office/site the person belongs to."
          },
          "manager": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Manager"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "email",
          "user",
          "name",
          "slack",
          "jobTitle",
          "department",
          "team",
          "site",
          "manager"
        ],
        "description": "The current SSO viewer, enriched with directory fields when the directory knows them."
      },
      "PlatformInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "const": "rink"
          },
          "release": {
            "type": "string",
            "description": "Deployed git hash, or `dev`."
          },
          "apiVersion": {
            "type": "string",
            "description": "Rink API version."
          },
          "sdk": {
            "type": "object",
            "properties": {
              "path": {
                "type": "string"
              },
              "platformInfo": {
                "type": "string"
              }
            },
            "required": [
              "path",
              "platformInfo"
            ]
          },
          "clients": {
            "type": "object",
            "description": "Supported client versions (e.g. `salming.minimumRinkVersion`).",
            "additionalProperties": true
          },
          "capabilities": {
            "type": "object",
            "description": "Live capability manifest: deploy, domains, aiChat, identity, directory, data, sql, shares, githubIssue and bigquery limits and flags.",
            "additionalProperties": true
          }
        },
        "required": [
          "name",
          "release",
          "apiVersion",
          "sdk",
          "clients",
          "capabilities"
        ]
      },
      "Doc": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "data": {
            "description": "The stored JSON value (any JSON type)."
          },
          "created_by": {
            "type": "string",
            "format": "email",
            "description": "Immutable creator email (server-owned)."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "data",
          "created_by",
          "created_at",
          "updated_at"
        ],
        "description": "rink.db document envelope. Rink owns id and the audit fields."
      },
      "DataPermissions": {
        "type": "object",
        "properties": {
          "create": {
            "type": "boolean"
          },
          "update": {
            "type": "boolean"
          },
          "delete": {
            "type": "boolean"
          }
        },
        "required": [
          "create",
          "update",
          "delete"
        ],
        "description": "Mutations the current viewer may perform under the collection's server-enforced policy."
      },
      "FormSubmission": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Doc"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "object",
                "properties": {
                  "form": {
                    "type": "string"
                  },
                  "values": {
                    "description": "The submitted JSON value."
                  },
                  "submittedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": [
                  "form",
                  "values",
                  "submittedAt"
                ]
              }
            }
          }
        ],
        "description": "A form submission: a Doc in collection `form_{name}` whose data is `{ form, values, submittedAt }`."
      },
      "FileMeta": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Sanitized file name (max 200 chars)."
          },
          "content_type": {
            "type": "string",
            "description": "MIME type as given at upload (max 200 chars)."
          },
          "size": {
            "type": "integer",
            "description": "Size in bytes."
          },
          "created_by": {
            "type": "string",
            "format": "email"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "url": {
            "type": "string",
            "description": "Same-origin URL serving the bytes: `/_rink/files/{id}`."
          }
        },
        "required": [
          "id",
          "name",
          "content_type",
          "size",
          "created_by",
          "created_at",
          "url"
        ]
      },
      "GeoPoint": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          }
        },
        "required": [
          "latitude",
          "longitude"
        ]
      },
      "Office": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "countryCode": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact": {
            "type": "object",
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "phone": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "email"
            ]
          },
          "coordinates": {
            "$ref": "#/components/schemas/GeoPoint"
          },
          "approximate": {
            "type": "boolean",
            "description": "True when the coordinates are approximate."
          }
        },
        "required": [
          "id",
          "name",
          "city",
          "country",
          "countryCode",
          "timezone",
          "address",
          "contact",
          "coordinates",
          "approximate"
        ],
        "description": "A SeenThis office."
      },
      "ApproximateLocation": {
        "type": "object",
        "properties": {
          "accuracy": {
            "type": "string",
            "const": "approximate"
          },
          "source": {
            "type": "string",
            "enum": [
              "headers",
              "ip"
            ]
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "countryCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "accuracy",
          "source",
          "city",
          "region",
          "country",
          "countryCode",
          "timezone"
        ],
        "description": "Coarse location inferred from edge headers or the viewer IP. Coordinates may be absent; never treat as precise."
      },
      "WeatherInput": {
        "type": "object",
        "properties": {
          "office": {
            "type": "string",
            "description": "SeenThis office id, name, city or country (normalized). Takes precedence over coordinates."
          },
          "latitude": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "longitude": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          }
        },
        "description": "`{ office }` or `{ latitude, longitude }`."
      },
      "WeatherLocation": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          },
          "label": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "office": {
            "$ref": "#/components/schemas/Office"
          }
        },
        "required": [
          "latitude",
          "longitude",
          "label"
        ]
      },
      "CurrentWeather": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "const": "open-meteo"
          },
          "location": {
            "$ref": "#/components/schemas/WeatherLocation"
          },
          "current": {
            "type": [
              "object",
              "null"
            ],
            "description": "Open-Meteo `current` block: temperature_2m, apparent_temperature, relative_humidity_2m, precipitation, weather_code, wind_speed_10m (plus time/interval).",
            "additionalProperties": true
          },
          "units": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "source",
          "location",
          "current",
          "units"
        ]
      },
      "WeatherForecast": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "const": "open-meteo"
          },
          "location": {
            "$ref": "#/components/schemas/WeatherLocation"
          },
          "daily": {
            "type": [
              "object",
              "null"
            ],
            "description": "Open-Meteo `daily` block: time, weather_code, temperature_2m_max, temperature_2m_min, precipitation_sum arrays.",
            "additionalProperties": true
          },
          "units": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "source",
          "location",
          "daily",
          "units"
        ]
      },
      "GitHubIssue": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "repo": {
            "type": "string",
            "description": "`owner/repository`."
          },
          "number": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "assignees": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "login": {
                  "type": "string"
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "login",
                "name"
              ]
            }
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "url",
          "repo",
          "number",
          "title",
          "state",
          "assignees",
          "updatedAt"
        ]
      },
      "SqlValue": {
        "description": "A SQL binding: string, finite number, boolean (stored as 0/1), null, `{ $rink: 'bigint', value }` or `{ $rink: 'blob', base64 }`.",
        "anyOf": [
          {
            "type": [
              "string",
              "number",
              "boolean",
              "null"
            ]
          },
          {
            "type": "object",
            "properties": {
              "$rink": {
                "type": "string",
                "const": "bigint"
              },
              "value": {
                "type": "string",
                "pattern": "^-?\\d+$"
              }
            },
            "required": [
              "$rink",
              "value"
            ]
          },
          {
            "type": "object",
            "properties": {
              "$rink": {
                "type": "string",
                "const": "blob"
              },
              "base64": {
                "type": "string"
              }
            },
            "required": [
              "$rink",
              "base64"
            ]
          }
        ]
      },
      "SqlRequest": {
        "type": "object",
        "properties": {
          "statement": {
            "type": "string",
            "description": "Exact statement name from the active deploy's rink.sql.json. Raw SQL is never accepted."
          },
          "params": {
            "description": "Positional array or named object of bindings (max 100). Names must match `^[a-zA-Z][a-zA-Z0-9_]{0,79}$`; `_rink_*` names are server-owned.",
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SqlValue"
                }
              },
              {
                "type": "object",
                "additionalProperties": {
                  "$ref": "#/components/schemas/SqlValue"
                }
              }
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "all",
              "first",
              "run",
              "raw"
            ]
          },
          "column": {
            "type": "string",
            "description": "For `first`: return only this column."
          },
          "columnNames": {
            "type": "boolean",
            "description": "For `raw`: prefix the rows with the column names."
          }
        },
        "required": [
          "statement"
        ]
      },
      "SqlResult": {
        "type": "object",
        "properties": {
          "results": {
            "description": "Rows (all), a row/column value/null (first), or row arrays (raw). Large integers are strings."
          },
          "success": {
            "type": "boolean",
            "const": true
          },
          "meta": {
            "type": "object",
            "properties": {
              "duration": {
                "type": "number"
              },
              "changes": {
                "type": "integer"
              },
              "last_row_id": {
                "type": [
                  "integer",
                  "string",
                  "null"
                ]
              },
              "rows_read": {
                "type": "integer"
              },
              "rows_written": {
                "type": "integer"
              },
              "generation": {
                "type": "integer"
              }
            },
            "required": [
              "duration",
              "changes",
              "last_row_id",
              "rows_read",
              "rows_written"
            ]
          }
        },
        "required": [
          "success",
          "meta"
        ],
        "description": "D1-style result envelope."
      },
      "EmailRequest": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "format": "email",
            "description": "One @seenthis address."
          },
          "subject": {
            "type": "string",
            "description": "Required; truncated to 200 characters."
          },
          "text": {
            "type": "string"
          },
          "html": {
            "type": "string"
          }
        },
        "required": [
          "to",
          "subject"
        ],
        "description": "At least one of text or html is required. Reply-To is always the authenticated viewer."
      },
      "HttpFetchResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "description": "Upstream HTTP status."
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Selected upstream headers (content-type, cache-control, etag, location, retry-after, rate-limit headers…)."
          },
          "body": {
            "type": "string",
            "description": "UTF-8 text, or base64 for binary responses. Occurrences of a used secret in common encodings are replaced by `[redacted]` (defense in depth; the host allowlist is the boundary). Empty when `bodyWithheld` is set."
          },
          "bodyWithheld": {
            "type": "string",
            "enum": [
              "status-only",
              "compressed"
            ],
            "description": "Present when the body is not returned: a used secret has responseAccess `status-only`, or the upstream sent a compressed archive."
          },
          "bodyEncoding": {
            "type": "string",
            "enum": [
              "text",
              "base64"
            ]
          }
        },
        "required": [
          "status",
          "headers",
          "body",
          "bodyEncoding"
        ]
      },
      "CronAction": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "webhook"
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "http(s); private and link-local destinations are rejected. With `{{secret:NAME}}` placeholders the call goes through rink.http.fetch rules (https, allowed hosts)."
              },
              "method": {
                "type": "string",
                "description": "Defaults to POST."
              },
              "headers": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "body": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "url"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "ai"
              },
              "prompt": {
                "type": "string"
              },
              "model": {
                "type": "string"
              },
              "collection": {
                "type": "string",
                "description": "Target rink.db collection; written through its create policy."
              }
            },
            "required": [
              "type",
              "prompt",
              "collection"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "email"
              },
              "to": {
                "type": "string",
                "format": "email",
                "description": "@seenthis address."
              },
              "subject": {
                "type": "string"
              },
              "text": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "to",
              "subject",
              "text"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "workflow"
              },
              "workflowId": {
                "type": "string",
                "format": "uuid"
              }
            },
            "required": [
              "type",
              "workflowId"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "bq.query"
              },
              "sql": {
                "type": "string",
                "description": "Read-only SELECT on the site's granted datasets."
              },
              "params": {
                "$ref": "#/components/schemas/BqParams"
              },
              "types": {
                "$ref": "#/components/schemas/BqTypes"
              },
              "maxRows": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000,
                "default": 1000
              },
              "then": {
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "collection": {
                        "type": "string",
                        "description": "rink.db collection that receives one snapshot document per run (rows trimmed to fit 256 KB)."
                      }
                    },
                    "required": [
                      "collection"
                    ]
                  },
                  {
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string",
                        "description": "@seenthis recipient of a CSV attachment."
                      },
                      "subject": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "email"
                    ]
                  }
                ]
              }
            },
            "required": [
              "type",
              "sql",
              "then"
            ]
          }
        ]
      },
      "CronJobInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "schedule": {
            "type": "string",
            "description": "Five-field cron expression evaluated in Europe/Stockholm."
          },
          "action": {
            "$ref": "#/components/schemas/CronAction"
          }
        },
        "required": [
          "schedule",
          "action"
        ]
      },
      "CronJob": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "schedule": {
            "type": "string"
          },
          "action": {
            "$ref": "#/components/schemas/CronAction"
          },
          "enabled": {
            "type": "boolean"
          },
          "created_by": {
            "type": "string"
          },
          "next_run": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_run": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_detail": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "schedule",
          "action",
          "enabled"
        ]
      },
      "WorkflowTrigger": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "schedule"
              },
              "cron": {
                "type": "string",
                "description": "Five-field cron expression."
              }
            },
            "required": [
              "type",
              "cron"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "form.submit"
              },
              "form": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "form"
            ]
          }
        ]
      },
      "WorkflowStep": {
        "description": "One step. String values may interpolate `{{event}}`, `{{previous}}`, `{{form}}` and `{{field.name}}`.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "weather.current"
              },
              "input": {
                "$ref": "#/components/schemas/WeatherInput"
              }
            },
            "required": [
              "type"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "db.create"
              },
              "collection": {
                "type": "string"
              },
              "data": {}
            },
            "required": [
              "type",
              "collection"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "email.send"
              },
              "to": {
                "type": "string",
                "description": "@seenthis address."
              },
              "subject": {
                "type": "string"
              },
              "text": {
                "type": "string"
              },
              "html": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "to",
              "subject"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "webhook.call"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "method": {
                "type": "string"
              },
              "headers": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "body": {}
            },
            "required": [
              "type",
              "url"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "bq.query"
              },
              "sql": {
                "type": "string",
                "description": "Read-only SELECT; never templated."
              },
              "params": {
                "type": "object",
                "additionalProperties": true,
                "description": "Named @params; string values may use placeholders."
              },
              "types": {
                "$ref": "#/components/schemas/BqTypes"
              },
              "maxRows": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000,
                "default": 1000
              }
            },
            "required": [
              "type",
              "sql"
            ]
          }
        ]
      },
      "WorkflowInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Defaults to `Workflow`."
          },
          "trigger": {
            "$ref": "#/components/schemas/WorkflowTrigger"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStep"
            },
            "minItems": 1,
            "maxItems": 10
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "trigger",
          "steps"
        ]
      },
      "Workflow": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Doc"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "trigger": {
                    "$ref": "#/components/schemas/WorkflowTrigger"
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/WorkflowStep"
                    }
                  },
                  "enabled": {
                    "type": "boolean"
                  },
                  "cronJobId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Backing schedule job for schedule triggers."
                  },
                  "createdAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "updatedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": [
                  "name",
                  "trigger",
                  "steps",
                  "enabled",
                  "cronJobId",
                  "createdAt",
                  "updatedAt"
                ]
              }
            }
          }
        ],
        "description": "A workflow definition Doc in the Rink-owned `workflow_defs` collection."
      },
      "WorkflowRun": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Doc"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "object",
                "properties": {
                  "workflowId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "workflowName": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "error"
                    ]
                  },
                  "event": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "manual",
                          "schedule",
                          "form.submit"
                        ]
                      },
                      "form": {
                        "type": "string"
                      },
                      "submissionId": {
                        "type": "string"
                      },
                      "values": {}
                    },
                    "required": [
                      "type"
                    ]
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "index": {
                          "type": "integer"
                        },
                        "type": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "ok",
                            "error"
                          ]
                        },
                        "result": {},
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "index",
                        "type",
                        "status"
                      ]
                    }
                  },
                  "result": {
                    "description": "The last successful step result."
                  },
                  "startedAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "finishedAt": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": [
                  "workflowId",
                  "workflowName",
                  "status",
                  "event",
                  "steps",
                  "startedAt",
                  "finishedAt"
                ]
              }
            }
          }
        ],
        "description": "A workflow run record Doc in the Rink-owned `workflow_runs` collection."
      },
      "ChatContentBlock": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "text"
              },
              "text": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "text"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "image"
              },
              "source": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "base64"
                  },
                  "media_type": {
                    "type": "string",
                    "enum": [
                      "image/jpeg",
                      "image/png",
                      "image/gif",
                      "image/webp"
                    ]
                  },
                  "data": {
                    "type": "string",
                    "description": "Unprefixed base64, max 7 MB decoded."
                  }
                },
                "required": [
                  "type",
                  "media_type",
                  "data"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "type",
              "source"
            ],
            "additionalProperties": false,
            "description": "User messages only; Claude models only."
          }
        ]
      },
      "ChatMessage": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "user",
              "assistant"
            ]
          },
          "content": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ChatContentBlock"
                },
                "minItems": 1,
                "maxItems": 100
              }
            ]
          }
        },
        "required": [
          "role",
          "content"
        ]
      },
      "ChatRequest": {
        "type": "object",
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            },
            "minItems": 1,
            "maxItems": 100
          },
          "system": {
            "type": "string",
            "description": "Non-empty, max 200,000 characters."
          },
          "model": {
            "type": "string",
            "description": "Defaults to claude-sonnet-4-6. Allowed: claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5, opus, sonnet, haiku, gemini-3.5-flash, gemini-3-pro-preview, gemini-2.5-flash, gemini, gemini-flash, gemini-pro."
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "default": 1024,
            "description": "Clamped to 16,384."
          }
        },
        "required": [
          "messages"
        ],
        "description": "At most 4 images per request, 7 MB each and 10 MB total."
      },
      "ChatResponse": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "Generated text."
          },
          "model": {
            "type": "string",
            "description": "Resolved provider model id."
          },
          "usage": {
            "type": "object",
            "properties": {
              "input_tokens": {
                "type": "integer"
              },
              "output_tokens": {
                "type": "integer"
              }
            },
            "required": [
              "input_tokens",
              "output_tokens"
            ],
            "additionalProperties": true,
            "description": "Token usage (the Anthropic usage object for Claude models)."
          }
        },
        "required": [
          "content",
          "model",
          "usage"
        ]
      },
      "GenerateMediaRequest": {
        "type": "object",
        "properties": {
          "prompt": {
            "type": "string",
            "minLength": 1
          },
          "model": {
            "type": "string",
            "description": "Allowlisted model or alias; unknown values fall back to the default model."
          }
        },
        "required": [
          "prompt"
        ]
      },
      "VideoJobStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "done",
              "error"
            ]
          },
          "file": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileMeta"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "status"
        ],
        "description": "`done` includes the stored file; `error` includes an error message."
      },
      "SharePermissions": {
        "type": "object",
        "properties": {
          "create": {
            "type": "boolean"
          },
          "manage": {
            "type": "boolean"
          },
          "readStats": {
            "type": "boolean"
          },
          "manageAll": {
            "type": "boolean"
          },
          "configure": {
            "type": "boolean"
          }
        },
        "required": [
          "create",
          "manage",
          "readStats",
          "manageAll",
          "configure"
        ]
      },
      "Share": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdBy": {
            "type": "string"
          },
          "sharedWithSite": {
            "type": "boolean"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "destination": {
            "type": [
              "string",
              "null"
            ]
          },
          "file": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "size": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "name",
                  "size",
                  "sha256"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "passwordProtected": {
            "type": "boolean"
          },
          "state": {
            "type": "string",
            "enum": [
              "draft",
              "pending_review",
              "published",
              "blocked",
              "expired",
              "revoked",
              "unavailable"
            ],
            "description": "Only `published` means publicly available."
          },
          "url": {
            "type": "string",
            "description": "Public share URL on the site's public host."
          },
          "review": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "deployId": {
                    "type": "string"
                  },
                  "security": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "public": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "deployId",
                  "security",
                  "public"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "permissions": {
            "$ref": "#/components/schemas/SharePermissions"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "createdBy",
          "sharedWithSite",
          "title",
          "slug",
          "destination",
          "file",
          "expiresAt",
          "passwordProtected",
          "state",
          "url",
          "review",
          "permissions",
          "createdAt",
          "updatedAt"
        ]
      },
      "ShareCreate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]{0,79}$",
            "description": "Reserved paths are rejected."
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "password": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 8,
            "maxLength": 256
          },
          "fileId": {
            "type": "string",
            "format": "uuid",
            "description": "Existing rink.files upload. Exactly one of fileId or destination."
          },
          "destination": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "HTTP(S) URL without credentials."
          },
          "ownerEmail": {
            "type": "string",
            "format": "email",
            "description": "Share administrators only."
          },
          "sharedWithSite": {
            "type": "boolean",
            "description": "Share administrators only."
          }
        },
        "required": [
          "title",
          "slug"
        ],
        "additionalProperties": false
      },
      "ShareUpdate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]{0,79}$"
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "password": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 8,
            "maxLength": 256,
            "description": "null removes the password."
          }
        },
        "additionalProperties": false
      },
      "SharePolicyInput": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "admins": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "maxItems": 100
          }
        },
        "required": [
          "enabled",
          "admins"
        ],
        "additionalProperties": false
      },
      "SharePolicy": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "permissions": {
            "$ref": "#/components/schemas/SharePermissions"
          },
          "admins": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Only present when the viewer may configure sharing."
          }
        },
        "required": [
          "enabled",
          "permissions"
        ]
      },
      "ShareStats": {
        "type": "object",
        "properties": {
          "views": {
            "type": "string",
            "description": "Total (bigint as string)."
          },
          "downloads": {
            "type": "string",
            "description": "Total (bigint as string). An authorized request, not a completed transfer."
          },
          "outbound_clicks": {
            "type": "string",
            "description": "Total (bigint as string)."
          },
          "retentionDays": {
            "type": "integer",
            "const": 90
          },
          "daily": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "day": {
                  "type": "string",
                  "format": "date"
                },
                "views": {
                  "type": "string"
                },
                "downloads": {
                  "type": "string"
                },
                "outbound_clicks": {
                  "type": "string"
                }
              },
              "required": [
                "day",
                "views",
                "downloads",
                "outbound_clicks"
              ]
            },
            "description": "Days with recorded requests; omitted days are zero."
          }
        },
        "required": [
          "views",
          "downloads",
          "outbound_clicks",
          "retentionDays",
          "daily"
        ]
      },
      "BqParams": {
        "type": "object",
        "description": "Named `@param` values. SQL text is never interpolated. Strings coerce to DATE/TIMESTAMP where BigQuery allows it.",
        "additionalProperties": {
          "anyOf": [
            {
              "type": [
                "string",
                "number",
                "boolean",
                "null"
              ]
            },
            {
              "type": "array",
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean",
                  "null"
                ]
              }
            }
          ]
        },
        "maxProperties": 100
      },
      "BqTypes": {
        "type": "object",
        "description": "Optional parameter types, e.g. `{ from: 'DATE' }` or `{ ids: ['INT64'] }`. Required for null values and empty arrays.",
        "additionalProperties": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              },
              "minItems": 1,
              "maxItems": 1
            }
          ]
        }
      },
      "BqQueryRequest": {
        "type": "object",
        "properties": {
          "sql": {
            "type": "string",
            "description": "BigQuery Standard SQL. One read-only SELECT on datasets granted to this site; max 64 KB."
          },
          "params": {
            "$ref": "#/components/schemas/BqParams"
          },
          "types": {
            "$ref": "#/components/schemas/BqTypes"
          },
          "cacheTtl": {
            "type": "integer",
            "minimum": 0,
            "maximum": 86400,
            "default": 300,
            "description": "Seconds to reuse a shared result from the Rink cache; 0 disables it."
          },
          "maxRows": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000,
            "default": 10000,
            "description": "Rows per page (pages are also capped at 10 MB)."
          },
          "pageToken": {
            "type": "string",
            "description": "Continue a previous result instead of running `sql`. Pass the same `as` as the query that created it."
          },
          "as": {
            "type": "string",
            "enum": [
              "me"
            ],
            "description": "Run with your own connected Google account (My account → Connected accounts at /account) instead of the site's shared service account: Google IAM of the signed-in user decides what can be read, so no site dataset grant is needed. Owners and editors of the site only, on internal hosts, never cached by Rink. The same SELECT-only dry run, maximumBytesBilled reservation, site and per-user daily caps and labels (plus `rink_identity: user`) apply."
          },
          "location": {
            "type": "string",
            "description": "Dataset location (e.g. EU, US) for `as: \"me\"` queries; defaults to the location of a granted dataset the SQL names, else the Rink default."
          }
        },
        "description": "Either `sql` (new query) or `pageToken` (next page)."
      },
      "BqField": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "BigQuery type, e.g. STRING, INT64, FLOAT64, NUMERIC, DATE, TIMESTAMP, RECORD."
          },
          "mode": {
            "type": "string",
            "description": "NULLABLE, REQUIRED or REPEATED."
          },
          "description": {
            "type": "string"
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BqField"
            }
          }
        },
        "required": [
          "name",
          "type"
        ]
      },
      "BqQueryResult": {
        "type": "object",
        "properties": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BqField"
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "INT64 outside the safe integer range, NUMERIC and BIGNUMERIC are strings; TIMESTAMP is ISO 8601."
          },
          "totalRows": {
            "type": "integer"
          },
          "bytesBilled": {
            "type": "integer",
            "description": "Bytes charged to the site's budget for this call (0 for Rink cache hits and further pages; the full reservation when BigQuery hides billing statistics)."
          },
          "bytesProcessed": {
            "type": [
              "integer",
              "null"
            ],
            "description": "null when BigQuery withholds the statistic (row-level security)."
          },
          "billingHidden": {
            "type": "boolean",
            "description": "BigQuery withheld billing statistics (row-level security); the job's full reservation was charged."
          },
          "costUsd": {
            "type": "number"
          },
          "cacheHit": {
            "type": "boolean"
          },
          "cache": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "rink",
              "bigquery",
              null
            ]
          },
          "jobId": {
            "type": "string"
          },
          "pageToken": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass to rink.bq.nextPage() for more rows; null on the last page."
          }
        },
        "required": [
          "schema",
          "rows",
          "totalRows",
          "bytesBilled",
          "cacheHit",
          "jobId",
          "pageToken"
        ]
      },
      "BqCaps": {
        "type": "object",
        "properties": {
          "maxBytesPerQuery": {
            "type": "integer",
            "description": "maximumBytesBilled per query (default 100 GB)."
          },
          "siteDailyBytes": {
            "type": "integer"
          },
          "viewerDailyBytes": {
            "type": "integer"
          }
        },
        "required": [
          "maxBytesPerQuery",
          "siteDailyBytes",
          "viewerDailyBytes"
        ]
      },
      "BqEstimate": {
        "type": "object",
        "properties": {
          "statementType": {
            "type": "string"
          },
          "bytesProcessed": {
            "type": "integer"
          },
          "costUsd": {
            "type": "number"
          },
          "datasets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "location": {
            "type": "string"
          },
          "caps": {
            "$ref": "#/components/schemas/BqCaps"
          },
          "siteBytesToday": {
            "type": "integer"
          },
          "viewerBytesToday": {
            "type": [
              "integer",
              "null"
            ]
          },
          "allowed": {
            "type": "boolean"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the query would be refused by a cost cap."
          }
        },
        "required": [
          "statementType",
          "bytesProcessed",
          "costUsd",
          "datasets",
          "caps",
          "allowed"
        ]
      },
      "BqDataset": {
        "type": "object",
        "properties": {
          "dataset": {
            "type": "string",
            "description": "`project.dataset`, e.g. seenthis-insights.dwh."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "notes": {
            "type": "string",
            "description": "Curated notes from the catalog: business meaning, units, partition column."
          },
          "owner": {
            "type": "string",
            "description": "Data owner email."
          },
          "sensitivity": {
            "type": "string",
            "enum": [
              "internal",
              "restricted"
            ]
          },
          "location": {
            "type": "string"
          }
        },
        "required": [
          "dataset",
          "title",
          "owner",
          "sensitivity"
        ]
      },
      "BqTable": {
        "type": "object",
        "properties": {
          "table": {
            "type": "string",
            "description": "Fully qualified `project.dataset.table`."
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "BASE TABLE, VIEW, MATERIALIZED VIEW, …"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "rowCount": {
            "type": [
              "integer",
              "null"
            ]
          },
          "sizeBytes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "partitioning": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Partition column(s): filter on these in every query."
          },
          "clustering": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "Curated table notes."
          }
        },
        "required": [
          "table",
          "name",
          "type",
          "partitioning",
          "clustering"
        ]
      },
      "BqTableSchema": {
        "type": "object",
        "properties": {
          "table": {
            "type": "string"
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BqField"
            },
            "description": "Columns with nested RECORD fields."
          },
          "partitioning": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "clustering": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "datasetNotes": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "table",
          "columns",
          "partitioning",
          "clustering"
        ]
      }
    }
  }
}