{"openapi":"3.1.0","info":{"title":"spotlights API","version":"1.4.0","description":"Durable guided tours in private tenant libraries. Users and tenants have separate IDs; memberships control access. Register or sign in with email, password and a public installation key, then exchange a signed challenge for a ten-minute access token. Device sessions expire after 30 days or on sign-out. Tenant owners create email-bound invitation codes and links. A user may accept one invitation in their lifetime; joining revokes all previous tenant memberships, sessions and AI grants. The workspaceId path parameter is the tenant ID, checked against the authenticated session. PostgreSQL enforces tenant row security. Sign in at /library before using authenticated operations in this explorer. Release notes and version endpoints are public."},"servers":[{"url":"/","description":"Current spotlights service"}],"tags":[{"name":"Service","description":"Service availability."},{"name":"Accounts","description":"Accounts, tenant memberships and invitation links."},{"name":"Installations","description":"Key-bound sessions, short-lived authorization and sign-out."},{"name":"Tours","description":"Tenant tours, immutable versions and archive. Lists contain up to 25 tours. Saves accept schema 1 JSON up to 500,000 bytes and 100 steps."}],"security":[{"InstallationToken":[],"DeviceProof":[]}],"paths":{"/.well-known/oauth-authorization-server":{"get":{"operationId":"getOAuthMetadata","tags":["AI connections"],"summary":"Discover the OAuth authorization server","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"security":[]}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"getOAuthResource","tags":["AI connections"],"summary":"Discover the protected MCP resource","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"security":[]}},"/.well-known/oauth-protected-resource/mcp":{"get":{"operationId":"getMcpResource","tags":["AI connections"],"summary":"Discover the protected MCP resource at /mcp","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"security":[]}},"/oauth/register":{"post":{"operationId":"registerOAuthClient","tags":["AI connections"],"summary":"Register an MCP client automatically","responses":{"201":{"description":"Public client registered","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid client metadata"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_name":{"type":"string","maxLength":120},"redirect_uris":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"string","format":"uri"}},"token_endpoint_auth_method":{"const":"none"}},"required":["redirect_uris"]}}}},"security":[]}},"/oauth/token":{"post":{"operationId":"exchangeOAuthToken","tags":["AI connections"],"summary":"Exchange a PKCE authorization code or rotate a refresh token","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token"]},"client_id":{"type":"string","format":"uuid"},"code":{"type":"string"},"redirect_uri":{"type":"string"},"code_verifier":{"type":"string","minLength":43,"maxLength":128},"refresh_token":{"type":"string"},"resource":{"type":"string"}},"required":["grant_type","client_id"]}}}},"security":[],"description":"Accepts JSON or application/x-www-form-urlencoded. A code exchange requires code, redirect_uri and code_verifier. Refresh requires refresh_token. Credentials are resource- and tenant-bound; refresh reuse revokes the connection."}},"/oauth/revoke":{"post":{"operationId":"revokeOAuthToken","tags":["AI connections"],"summary":"Revoke the connection associated with an access or refresh token","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string","format":"uuid"},"token":{"type":"string"}},"required":["client_id","token"]}}}},"security":[]}},"/api/v1/oauth/request":{"get":{"operationId":"reviewOAuthRequest","tags":["AI connections"],"summary":"Validate an assistant’s authorization request before showing consent","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"parameters":[{"name":"response_type","in":"query","schema":{"const":"code"},"required":true},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"},"required":true},{"name":"redirect_uri","in":"query","schema":{"type":"string","format":"uri"},"required":true},{"name":"code_challenge","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"},"required":true},{"name":"code_challenge_method","in":"query","schema":{"const":"S256"},"required":true},{"name":"scope","in":"query","schema":{"type":"string","enum":["tours:read","tours:read tours:write"]},"required":false},{"name":"state","in":"query","schema":{"type":"string","maxLength":2048},"required":false},{"name":"resource","in":"query","schema":{"type":"string","format":"uri"},"required":false}]}},"/api/v1/oauth/decision":{"post":{"operationId":"decideOAuthRequest","tags":["AI connections"],"summary":"Approve or deny AI access to a library you belong to","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"response_type":{"const":"code"},"client_id":{"type":"string","format":"uuid"},"redirect_uri":{"type":"string","format":"uri"},"code_challenge":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"},"code_challenge_method":{"const":"S256"},"scope":{"type":"string","enum":["tours:read","tours:read tours:write"]},"state":{"type":"string","maxLength":2048},"resource":{"type":"string","format":"uri"},"tenantId":{"type":"string","format":"uuid"},"approve":{"type":"boolean"}},"required":["response_type","client_id","redirect_uri","code_challenge","code_challenge_method","tenantId","approve"]}}}},"description":"The browser must explicitly obtain user consent. Returns a validated redirect URL carrying a one-use code or access_denied and the original state. Never gives an AI client the account password."}},"/api/v1/oauth/connections":{"get":{"operationId":"listAIConnections","tags":["AI connections"],"summary":"List your active AI connections to the current tenant","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}}}},"/api/v1/oauth/connections/{connectionId}":{"parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"disconnectAI","tags":["AI connections"],"summary":"Revoke your AI connection immediately","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}}}},"/api/v1/oauth/tools":{"get":{"operationId":"listAITools","tags":["AI connections"],"summary":"Describe available MCP tools and required scopes","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}}}},"/mcp":{"post":{"operationId":"callMcp","tags":["AI connections"],"summary":"Streamable HTTP MCP endpoint","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid OAuth request"},"401":{"description":"Sign-in or a valid OAuth token is required"},"403":{"description":"Access denied"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"const":"2.0"},"id":{"type":["string","number"]},"method":{"type":"string"},"params":{"type":"object","additionalProperties":true}},"required":["jsonrpc","method"]}}}},"security":[{"McpOAuth":["tours:read"]}],"description":"Use an MCP client. Supports initialize, ping, tools/list and tools/call. Send Accept: application/json, text/event-stream. Mutating tools require tours:write. Tokens authorize one user and tenant; tenant IDs are not tool arguments."}},"/health":{"get":{"operationId":"getHealth","tags":["Service"],"summary":"Check service health","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"ok","type":"string"},"service":{"const":"spotlights-portal","type":"string"}},"required":["status","service"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/api/v1/auth/register":{"post":{"operationId":"createAccount","tags":["Accounts"],"summary":"Create an account and its first tenant, or accept an invitation","responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Installation"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"DeviceProof":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountCredentials"}}}}}},"/api/v1/auth/login":{"post":{"operationId":"signIn","tags":["Accounts"],"summary":"Sign in on this installation","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Installation"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"DeviceProof":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountCredentials"}}}}}},"/api/v1/auth/logout":{"post":{"operationId":"signOut","tags":["Accounts"],"summary":"Sign out and revoke this installation session","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/auth/tenant":{"post":{"operationId":"switchTenant","tags":["Accounts"],"summary":"Switch to a tenant you belong to","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Installation"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tenantId":{"type":"string","format":"uuid"}},"required":["tenantId"]}}}}}},"/api/v1/invitations/accept":{"post":{"operationId":"acceptInvitation","tags":["Accounts"],"summary":"Join a tenant once and revoke access to previous tenants","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Installation"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Use the invited email account. This atomically accepts the invitation, revokes previous memberships and their browser/AI credentials, and connects the new tenant. The same accepted code may be retried; a different code is rejected forever. Historical tours are preserved.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","maxLength":2048,"description":"Invitation code or link; legacy 43-character tokens also work."}},"required":["token"]}}}}}},"/api/v1/workspaces/{workspaceId}/invitations":{"parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"inviteUser","tags":["Accounts"],"summary":"Create a seven-day invitation code and link (owner only)","responses":{"201":{"description":"Share this code or link with the invited person","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","maxLength":254},"tenantId":{"type":"string","format":"uuid"},"expiresAt":{"type":"integer"},"code":{"type":"string","maxLength":24},"url":{"type":"string"}},"required":["id","email","tenantId","expiresAt","code","url"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email"}},"required":["email"]}}}}}},"/api/v1/version":{"get":{"operationId":"getVersion","tags":["Service"],"summary":"Get the version and commit currently serving requests","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"service":{"type":"string"},"version":{"type":"string"},"extension_version":{"type":["string","null"],"description":"Associated extension package version; not a Chrome Web Store publication status."},"commit_sha":{"type":["string","null"]},"build_number":{"type":["integer","null"]}},"required":["service","version","extension_version","commit_sha","build_number"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/api/v1/release-notes":{"get":{"operationId":"getReleaseNotes","tags":["Service"],"summary":"List deployed release notes","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReleaseNote"}},"nextOffset":{"type":["integer","null"],"description":"Offset for the next page, or null at the end."}},"required":["items","nextOffset"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"description":"Maximum number of releases."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0},"description":"Number of newer releases to skip."}]}},"/api/v1/devices/{deviceId}/challenge":{"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"createChallenge","tags":["Installations"],"summary":"Get a one-use challenge","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"nonce":{"type":"string","pattern":"^[\\w-]{43}$"}},"required":["nonce"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/api/v1/devices/{deviceId}/token":{"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"createAccessToken","tags":["Installations"],"summary":"Exchange a signed challenge for access","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accessToken":{"type":"string","pattern":"^[\\w-]{43}$"},"expiresAt":{"type":"integer","description":"Unix time in milliseconds."}},"required":["accessToken","expiresAt"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"DeviceProof":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nonce":{"type":"string","pattern":"^[\\w-]{43}$"}},"required":["nonce"]}}}}}},"/api/v1/me":{"get":{"operationId":"getCurrentInstallation","tags":["Installations"],"summary":"Get this installation and its library","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string","format":"uuid"},"user":{"$ref":"#/components/schemas/User"},"canAcceptInvitation":{"type":"boolean"},"tenantId":{"type":"string","format":"uuid"},"tenantRole":{"type":"string"},"tenants":{"type":"array","items":{"$ref":"#/components/schemas/Tenant"}},"workspaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"$ref":"#/components/schemas/Role"}},"required":["id","name","role"]}}},"required":["deviceId","user","canAcceptInvitation","tenantId","tenantRole","tenants","workspaces"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/workspaces/{workspaceId}/tours":{"parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listTours","tags":["Tours"],"summary":"Browse and search tours","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","maxItems":25,"items":{"$ref":"#/components/schemas/TourSummary"}},"nextCursor":{"type":["string","null"],"format":"uuid"}},"required":["items","nextCursor"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":120},"description":"Search tour names, descriptions and tags."},{"name":"origin","in":"query","schema":{"type":"string","maxLength":2048},"description":"Exact website origin, for example https://example.com."},{"name":"cursor","in":"query","schema":{"type":"string","format":"uuid"},"description":"nextCursor returned by the previous page."}]},"post":{"operationId":"createTour","tags":["Tours"],"summary":"Save a new tour","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedTour"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","format":"uuid"},"description":"Reuse the same UUID when retrying the same change. Use a new UUID for a different change."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveTour"}}}}}},"/api/v1/workspaces/{workspaceId}/tours/{tourId}":{"parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tourId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getTour","tags":["Tours"],"summary":"Load a tour","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TourDetail"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"version","in":"query","schema":{"type":"integer","minimum":1},"description":"An earlier version number; omit to load the latest."}]}},"/api/v1/workspaces/{workspaceId}/tours/{tourId}/versions":{"parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tourId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listTourVersions","tags":["Tours"],"summary":"List saved versions","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","maxItems":100,"items":{"type":"object","properties":{"version":{"type":"integer","minimum":1},"created_at":{"type":"string","format":"date-time"}},"required":["version","created_at"]}}},"required":["items"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Returns up to 100 versions. Requires author access."},"post":{"operationId":"saveTourVersion","tags":["Tours"],"summary":"Save a new version of your tour","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedTour"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Members of the active tenant can update the tour. baseRevision must match the current revision. Website origin cannot change.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","format":"uuid"},"description":"Reuse the same UUID when retrying the same change. Use a new UUID for a different change."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTour"}}}}}},"/api/v1/workspaces/{workspaceId}/tours/{tourId}/archive":{"parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tourId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"archiveTour","tags":["Tours"],"summary":"Archive your tour","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"archived":{"type":"boolean","const":true}},"required":["id","archived"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Members of the active tenant can archive a tour. Existing local copies are kept.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","format":"uuid"},"description":"Reuse the same UUID when retrying the same change. Use a new UUID for a different change."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"baseRevision":{"type":"integer","minimum":1}},"required":["baseRevision"]}}}}}},"/api/v1/workspaces/{workspaceId}/devices/{deviceId}":{"parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"deviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeInstallation","tags":["Installations"],"summary":"Revoke this installation","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, expired or replayed credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This installation cannot make this change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict or invitation already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invitation expired or unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"JSON body exceeds 500,000 bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Revokes only the calling installation and its access tokens. Signing in again creates a new authorized session."}}},"components":{"securitySchemes":{"McpOAuth":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"/oauth/authorize","tokenUrl":"/oauth/token","scopes":{"tours:read":"Find, read, export and validate tours","tours:write":"Create, update, copy and archive tours"}}}},"InstallationToken":{"type":"apiKey","in":"header","name":"Authorization","description":"DPoP <accessToken>. Tokens are bound to the installation key, not Bearer tokens."},"DeviceProof":{"type":"apiKey","in":"header","name":"DPoP","description":"A fresh ES256 JWT for every request, signed with the installation’s P-256 private key. Header: typ=dpop+jwt, alg=ES256, jwk=public key. Claims: jti (16–128 characters), iat (Unix seconds, within 60 seconds), htm (HTTP method), htu (absolute URL without query or fragment). Token exchange also requires nonce. Authorized requests also require ath (base64url SHA-256 of accessToken). Never reuse a proof."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]},"Role":{"type":"string","enum":["author","viewer"]},"PublicKey":{"type":"object","properties":{"kty":{"type":"string","const":"EC"},"crv":{"type":"string","const":"P-256"},"x":{"type":"string","pattern":"^[\\w-]{43}$"},"y":{"type":"string","pattern":"^[\\w-]{43}$"}},"required":["kty","crv","x","y"]},"AccountCredentials":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email"},"password":{"type":"string","maxLength":128,"minLength":12,"format":"password","writeOnly":true},"publicKey":{"$ref":"#/components/schemas/PublicKey"},"name":{"type":"string","maxLength":80},"invitation":{"type":"string","maxLength":2048,"description":"Optional invitation code or link. Joining is a one-time move that revokes previous tenant access."}},"required":["email","password","publicKey"]},"Tenant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","member"]}},"required":["id","name","role"]},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","maxLength":254,"format":"email"}},"required":["id","email"]},"Installation":{"type":"object","properties":{"status":{"type":"string","const":"connected"},"deviceId":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid"},"tenantRole":{"type":"string","enum":["owner","member"]},"workspaceName":{"type":"string"},"role":{"$ref":"#/components/schemas/Role"},"user":{"$ref":"#/components/schemas/User"},"canAcceptInvitation":{"type":"boolean"},"tenants":{"type":"array","items":{"$ref":"#/components/schemas/Tenant"}},"sessionExpiresAt":{"type":"integer"}},"required":["status","deviceId","workspaceId","tenantId","tenantRole","workspaceName","role","user","canAcceptInvitation","tenants","sessionExpiresAt"]},"ReleaseNote":{"type":"object","properties":{"version":{"type":"string"},"extension_version":{"type":["string","null"],"description":"Associated extension package version. Null for unknown historical versions; does not imply Store publication."},"build_number":{"type":["integer","null"]},"commit_sha":{"type":["string","null"]},"title":{"type":"string"},"notes":{"type":"array","items":{"type":"string"}},"staged_at":{"type":["string","null"],"format":"date-time"},"released_to_production_at":{"type":["string","null"],"format":"date-time"}},"required":["version","extension_version","build_number","commit_sha","title","notes","staged_at","released_to_production_at"]},"Tour":{"type":"object","properties":{"schema":{"type":"integer","const":1},"name":{"type":"string","maxLength":120,"minLength":1},"origin":{"type":"string","format":"uri","description":"Exact HTTP(S) origin, without a path or trailing slash.","examples":["https://example.com"]},"steps":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/Step"}}},"required":["schema","name","origin","steps"]},"Step":{"type":"object","properties":{"id":{"type":"string","maxLength":120,"minLength":1,"description":"Unique within the tour."},"title":{"type":"string","maxLength":120},"titleSource":{"type":"string","enum":["auto","custom"]},"body":{"type":"string","maxLength":2000},"mode":{"type":"string","enum":["manual","filled","click"]},"screen":{"type":"object","properties":{"pathname":{"type":"string","maxLength":2000,"pattern":"^/(?!/)","description":"Path without query, hash, whitespace or backslash."},"hash":{"type":"string","maxLength":500,"description":"Empty or a fragment starting with #."}},"required":["pathname"]},"locator":{"$ref":"#/components/schemas/Locator"}},"required":["id","mode","screen","locator"]},"TargetChain":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","properties":{"css":{"type":"string","maxLength":2000,"minLength":1},"text":{"type":"string","maxLength":200},"label":{"type":"string","maxLength":120}},"required":["css"]}},"EmbeddedFrame":{"type":"object","properties":{"origin":{"type":"string","maxLength":2048,"format":"uri","description":"Exact HTTP(S) origin. The chain identifies one application iframe in the main document, including shadow hosts."},"chain":{"$ref":"#/components/schemas/TargetChain"}},"required":["origin","chain"]},"Locator":{"type":"object","properties":{"chain":{"$ref":"#/components/schemas/TargetChain"},"frame":{"$ref":"#/components/schemas/EmbeddedFrame"},"expansion":{"type":"string","enum":["expand","collapse"],"description":"Desired disclosure state for a click step. Playback reads an already satisfied state and otherwise waits for the requested transition."},"label":{"type":"string","maxLength":120},"fragile":{"type":"boolean"},"kind":{"type":"string","enum":["text","select","checkable","radio","control","content"]}},"required":["chain"]},"SaveTour":{"type":"object","properties":{"tour":{"$ref":"#/components/schemas/Tour"},"description":{"type":"string","maxLength":2000},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}}},"required":["tour"]},"UpdateTour":{"type":"object","properties":{"tour":{"$ref":"#/components/schemas/Tour"},"description":{"type":"string","maxLength":2000},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}},"baseRevision":{"type":"integer","minimum":1}},"required":["tour","baseRevision"]},"SavedTour":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer","minimum":1},"revision":{"type":"integer","minimum":1}},"required":["id","version","revision"]},"TourSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid"},"version":{"type":"integer","minimum":1},"revision":{"type":"integer","minimum":1},"canEdit":{"type":"boolean"},"name":{"type":"string","maxLength":120},"origin":{"type":"string"},"description":{"type":"string","maxLength":2000},"tags":{"type":"array","items":{"type":"string","maxLength":40}},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tenantId","version","revision","canEdit","name","origin","description","tags","updatedAt"]},"TourDetail":{"allOf":[{"$ref":"#/components/schemas/TourSummary"},{"type":"object","properties":{"tour":{"$ref":"#/components/schemas/Tour"}},"required":["tour"]}]}}}}