{"openapi":"3.1.0","info":{"title":"Furnace v1 API","version":"1.0.0","description":"HTTP REST surface for the Furnace platform. Two-layer access: Bearer-token Layer-1 (`api:read` / `api:write`) gates whole verbs; per-namespace Layer-2 RBAC gates resource access. Use `/api/v1/auth/whoami` to verify your token resolves to the expected identity.\n\nPAT requests are limited to 600 requests per minute per user token, with a burst capacity of 100. The shared platform service key is exempt. Responses that run the limiter include `RateLimit` and `RateLimit-Policy`; exhausted requests return 429 with `Retry-After`.\n\n## Versioning and deprecation\n\nThe API is URL-versioned under `/api/v1`. Breaking changes ship under a new URL version. Removals use an expand/contract rollout and are announced as deprecated in this specification before removal."},"servers":[{"url":"https://api.falcata.io","description":"Production"},{"url":"https://{deployment}.convex.site","description":"Per-task ephemeral development deployment","variables":{"deployment":{"default":"carefree-otter-000","description":"Deployment name reported by `bun tools/convex-env.ts status --json`"}}}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Personal Access Token (PAT) issued via access-control, or the platform service key. Security requirements name the Layer-1 `api:read` or `api:write` permission required by each operation; these are RBAC requirements, not OAuth scope strings. Layer-2 RBAC is enforced per resource."},"oauth2":{"type":"oauth2","description":"OAuth 2.1 authorization-code flow with PKCE. The authorization server currently issues only the `full` OAuth scope.","flows":{"authorizationCode":{"authorizationUrl":"https://api.falcata.io/oauth/authorize","tokenUrl":"https://api.falcata.io/oauth/token","scopes":{"full":"Full OAuth scope; Furnace RBAC still controls each operation and resource."}}}}},"schemas":{"ApiError":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Machine-readable error code when the response defines one"}}},"PaginationMeta":{"type":"object","required":["total","hasMore"],"properties":{"total":{"type":"integer","minimum":0},"hasMore":{"type":"boolean"}}},"PatScope":{"type":"object","description":"Least-privilege narrowing for a Personal Access Token. Each field only restricts — a token without a scope carries the user’s full authority.","properties":{"readOnly":{"type":"boolean","description":"When true, write-mode routes and MCP tools are denied regardless of api:write grants."},"namespaces":{"type":"array","items":{"type":"string"},"description":"Allowlisted app namespaces. Omitted = every namespace the user can already reach."},"permissions":{"type":"array","items":{"type":"string"},"description":"Permission allowlist ANDed with the user’s bundle (wildcard-aware). Omitted = every permission the user holds."},"expiresAt":{"type":"integer","description":"Epoch milliseconds after which the token stops resolving. Omitted = never."}}},"CallerInfo":{"oneOf":[{"type":"object","required":["kind"],"properties":{"kind":{"const":"service"}}},{"type":"object","required":["kind"],"properties":{"kind":{"const":"pat"},"email":{"type":["string","null"]},"name":{"type":["string","null"]},"scope":{"$ref":"#/components/schemas/PatScope"}}}]},"MeBundle":{"type":["object","null"],"description":"Null when the account is banned, suspended, or deactivated.","properties":{"user":{"type":"object","required":["id","createdAt"],"properties":{"id":{"type":"string"},"email":{"type":["string","null"]},"name":{"type":["string","null"]},"status":{"type":"string","enum":["active","inactive"]},"emailSubscribed":{"type":"boolean"},"notificationPrefs":{"$ref":"#/components/schemas/MeNotificationPrefs"},"aiPrefs":{"$ref":"#/components/schemas/MeAiPrefs"},"lastLogin":{"type":["number","null"]},"createdAt":{"type":"number"}}},"profile":{"type":["object","null"],"description":"Display profile KV entry (name, avatarUrl, …).","properties":{"name":{"type":"string"},"avatarUrl":{"type":"string"}},"additionalProperties":true},"subscription":{"type":["object","null"],"description":"Deprecated: the legacy (marozzo) app subscription only. Use `subscriptions`.","properties":{"status":{"type":"string"},"tier":{"type":"string"},"currentPeriodEnd":{"type":"number"},"cancelAtPeriodEnd":{"type":"boolean"}}},"subscriptions":{"type":"array","description":"One entry per app the caller subscribes to.","items":{"$ref":"#/components/schemas/MeSubscription"}}}},"MeSubscription":{"type":"object","required":["app","appName","status","tier","currentPeriodEnd","cancelAtPeriodEnd"],"properties":{"app":{"type":"string","description":"App slug the subscription belongs to."},"appName":{"type":"string","description":"App display name."},"status":{"type":"string"},"tier":{"type":"string"},"currentPeriodEnd":{"type":"number"},"cancelAtPeriodEnd":{"type":"boolean"}}},"MeEmailConsent":{"type":"object","required":["namespace","appName","status","subscribed"],"properties":{"namespace":{"type":"string"},"appName":{"type":"string"},"status":{"type":["string","null"],"enum":["subscribed","unsubscribed","bounced","complained",null],"description":"Subscriber status; null when never subscribed."},"subscribed":{"type":"boolean"}}},"MeNotificationPrefs":{"type":"object","description":"Suppressible notification type → enabled. Opt-out model: a missing key means enabled.","additionalProperties":{"type":"boolean"}},"MeAiPrefs":{"type":"object","description":"Catalogued AI feature key → enabled. Opt-out model: a missing key means enabled.","additionalProperties":{"type":"boolean"}},"MeAiFeatures":{"type":"object","description":"AI feature key → composed availability. `enabled` is the AND of plan entitlement, your preference, and remaining budget; `reason` names the first one that failed.","additionalProperties":{"type":"object","required":["enabled","reason","preference","entitled","budget"],"properties":{"enabled":{"type":"boolean"},"reason":{"type":"string","enum":["ok","not_entitled","preference_off","budget_exhausted"]},"preference":{"type":"boolean","description":"Your stored choice, independent of the verdict."},"entitled":{"type":"boolean"},"budget":{"type":["object","null"],"description":"Null when nothing is capped, or when usage cannot be attributed (anonymous callers).","properties":{"window":{"type":"string","enum":["day","month"]},"used":{"type":"number"},"limit":{"type":"number"},"remaining":{"type":"number"},"exhausted":{"type":"boolean"}}}}}},"MePermissionBundle":{"type":"object","required":["roles","permissions","directPermissions","updatedAt"],"properties":{"roles":{"type":"array","items":{"type":"string"}},"permissions":{"type":"array","items":{"type":"string"}},"directPermissions":{"type":"array","items":{"type":"string"}},"updatedAt":{"type":"number"}}},"MeSession":{"type":"object","required":["id","createdAt","expiresAt"],"properties":{"id":{"type":"string"},"createdAt":{"type":"number"},"expiresAt":{"type":"number"}}},"FeedbackAttachment":{"type":"object","required":["storageKey","filename","mimeType","size","uploadedAt"],"properties":{"storageKey":{"type":"string"},"filename":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":"integer","minimum":0},"uploadedAt":{"type":"string","description":"ISO 8601 timestamp"}}},"Task":{"type":"object","required":["id","title","status","order","archived","createdAt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","enum":["todo","in_progress","done"]},"order":{"type":"number"},"archived":{"type":"boolean"},"createdAt":{"type":"integer","description":"Epoch ms"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/FeedbackAttachment"}},"description":{"type":"string","description":"Long-form markdown body."}}},"Board":{"type":"object","required":["id","name","ownerSubject","createdAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"ownerSubject":{"type":["string","null"],"description":"Owner subject; null only for the default board."},"createdAt":{"type":"integer","description":"Epoch ms"},"archived":{"type":"boolean"}}},"BoardSummary":{"type":"object","required":["board","role"],"properties":{"board":{"$ref":"#/components/schemas/Board"},"role":{"type":"string","enum":["owner","editor","viewer"],"description":"The caller's access level on this board."}}},"KvarkReminder":{"type":"object","required":["remindAt"],"properties":{"remindAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"recurrence":{"type":"string","enum":["daily","weekdays","weekly","monthly"]},"firedAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"channel":{"type":"string","enum":["notification","email","both"]}}},"KvarkAutomationTask":{"type":"object","required":["id","title","titled","visibility","bodyReadable","tags","boardId","columnId","status","order","archived","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"visibility":{"type":"string","enum":["zero-knowledge","server-readable"]},"body":{"type":"string","description":"Plaintext body. Accepted only when the task is server-readable."},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"boardId":{"type":"string"},"status":{"type":"string","enum":["todo","in_progress","done"]},"dueAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"reminder":{"type":"object","properties":{"remindAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"recurrence":{"type":"string","enum":["daily","weekdays","weekly","monthly"]},"firedAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"channel":{"type":"string","enum":["notification","email","both"]}},"required":["remindAt"]},"titled":{"type":"boolean","description":"True when the identity stores a title; false for derived entry labels."},"bodyReadable":{"type":"boolean","description":"False when the zero-knowledge body is opaque."},"description":{"type":"string","description":"Compatibility alias of body."},"columnId":{"type":"string"},"order":{"type":"number"},"archived":{"type":"boolean"},"createdAt":{"type":"integer","minimum":0},"updatedAt":{"type":"integer","minimum":0}}},"KvarkBoard":{"type":"object","required":["id","name","entryColumnId","order","archived","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"entryColumnId":{"type":"string"},"terminalColumnId":{"type":"string"},"defaultCollectionId":{"type":"string"},"defaultVisibility":{"type":"string","enum":["zero-knowledge","server-readable"]},"ownerNukleonId":{"type":"string"},"order":{"type":"number"},"archived":{"type":"boolean"},"createdAt":{"type":"integer","minimum":0},"updatedAt":{"type":"integer","minimum":0}}},"KvarkBoardColumn":{"type":"object","required":["id","boardId","name","tone","order","archived","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"boardId":{"type":"string"},"name":{"type":"string"},"tone":{"type":"string","enum":["default","positive","warning","info"]},"order":{"type":"number"},"archived":{"type":"boolean"},"createdAt":{"type":"integer","minimum":0},"updatedAt":{"type":"integer","minimum":0}}},"KvarkBoardPlacement":{"type":"object","required":["itemId","boardId","columnId","order","createdAt","updatedAt"],"properties":{"itemId":{"type":"string"},"boardId":{"type":"string"},"columnId":{"type":"string"},"order":{"type":"number"},"createdAt":{"type":"integer","minimum":0},"updatedAt":{"type":"integer","minimum":0}}},"ContentAccess":{"type":"string","enum":["inherit","public","auth","membership"]},"ContentStatus":{"type":"string","enum":["draft","published","archived"]},"ContentSummary":{"type":"object","required":["id","title","description","tags","status","path","createdAt","updatedAt","publishedAt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"status":{"$ref":"#/components/schemas/ContentStatus"},"path":{"type":["string","null"]},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"publishedAt":{"type":["integer","null"]}}},"ContentVersion":{"type":"object","required":["body","savedAt","savedBy"],"properties":{"body":{"type":"string"},"savedAt":{"type":"integer"},"savedBy":{"type":"string"},"isPublished":{"type":"boolean"}}},"ContentAuthor":{"type":"object","properties":{"subject":{"type":"string"},"name":{"type":"string"}}},"ContentFeaturedImage":{"type":"object","required":["src","alt"],"properties":{"src":{"type":"string"},"alt":{"type":"string"},"caption":{"type":"string"},"blurhash":{"type":"string"},"assetId":{"type":"string"}}},"ContentTocEntry":{"type":"object","required":["id","text","level"],"properties":{"id":{"type":"string"},"text":{"type":"string"},"level":{"type":"integer"}}},"ContentDocument":{"type":"object","required":["id","title","description","tags","authors","draft","published","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"authors":{"type":"array","items":{"$ref":"#/components/schemas/ContentAuthor"}},"featuredImage":{"oneOf":[{"$ref":"#/components/schemas/ContentFeaturedImage"},{"type":"null"}]},"draft":{"type":"string","description":"Draft markdown body"},"published":{"type":["string","null"],"description":"Published markdown body, null if unpublished"},"toc":{"type":"array","items":{"$ref":"#/components/schemas/ContentTocEntry"}},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"publishedAt":{"type":["integer","null"]},"path":{"type":["string","null"],"description":"Resolved URL path within the namespace"},"customData":{"type":"object","additionalProperties":{"type":"string"}}}},"NavTreeNode":{"type":"object","required":["id","parentId","urlSegment","order","isCategory","status","access","cachedTitle"],"properties":{"id":{"type":"string"},"parentId":{"type":["string","null"]},"urlSegment":{"type":"string"},"order":{"type":"number"},"isCategory":{"type":"boolean"},"status":{"$ref":"#/components/schemas/ContentStatus"},"access":{"$ref":"#/components/schemas/ContentAccess"},"cachedTitle":{"type":"string"},"cachedDescription":{"type":["string","null"]},"hidden":{"type":"boolean","description":"Excluded from reader navigation; still addressable by URL"},"startsAt":{"type":["integer","null"],"description":"Epoch ms; reader visibility opens at this time"},"endsAt":{"type":["integer","null"],"description":"Epoch ms; reader visibility closes at this time"},"path":{"type":"string"}}},"NamespaceTree":{"type":"object","required":["nodes","updatedAt"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NavTreeNode"}},"updatedAt":{"type":"integer"}}},"ContentLayout":{"type":"object","required":["slug","label","document","createdAt","updatedAt","createdBy"],"properties":{"slug":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"document":{"type":"object","description":"SDL layout document in the layout profile: a Stack/Row/Grid/Split/… tree whose leaves include `ContentSlot` nodes, one per editable region. Statics only — no data, vars, bindings, or conditionals. Validated on write; an invalid document is rejected, never stored."},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"createdBy":{"type":"string"}}},"ContentLayoutInput":{"type":"object","required":["slug","label","document"],"properties":{"slug":{"type":"string","description":"Lowercase-kebab, max 64 chars; `default` and `custom` are reserved"},"label":{"type":"string","description":"Max 120 characters"},"description":{"type":"string","description":"Max 500 characters"},"document":{"type":"object","description":"SDL layout document in the layout profile: a Stack/Row/Grid/Split/… tree whose leaves include `ContentSlot` nodes, one per editable region. Statics only — no data, vars, bindings, or conditionals. Validated on write; an invalid document is rejected, never stored."}}},"AnalyticsOverview":{"type":"object","required":["pageViews","sessions","users","events","pageViewsTrend","sessionsTrend","usersTrend","eventsTrend"],"properties":{"pageViews":{"type":"integer"},"sessions":{"type":"integer"},"users":{"type":"integer"},"events":{"type":"integer"},"pageViewsTrend":{"type":"integer","description":"Percent change vs prior window of equal length"},"sessionsTrend":{"type":"integer"},"usersTrend":{"type":"integer"},"eventsTrend":{"type":"integer"}}},"TimeSeriesPoint":{"type":"object","required":["timestamp","date","value","sessions","users","anonymous"],"properties":{"timestamp":{"type":"integer","description":"Bucket start, epoch ms"},"date":{"type":"string","description":"YYYY-MM-DD"},"value":{"type":"integer"},"sessions":{"type":"integer"},"users":{"type":"integer"},"anonymous":{"type":"integer","description":"Sessions with no authenticated event"}}},"TopPath":{"type":"object","required":["path","events","sessions","users","anonymous","eventsPerSession"],"properties":{"path":{"type":"string"},"events":{"type":"integer"},"sessions":{"type":"integer"},"users":{"type":"integer"},"anonymous":{"type":"integer"},"eventsPerSession":{"type":"number"}}},"TopReferrer":{"type":"object","required":["referrer","sessions","users","anonymous"],"properties":{"referrer":{"type":"string"},"sessions":{"type":"integer"},"users":{"type":"integer"},"anonymous":{"type":"integer"}}},"EventNameStat":{"type":"object","required":["name","count"],"properties":{"name":{"type":"string"},"count":{"type":"integer"}}},"AnalyticsEvent":{"type":"object","required":["namespace","name","timestamp"],"properties":{"namespace":{"type":"string"},"name":{"type":"string"},"timestamp":{"type":"integer","description":"Event time, epoch ms"},"sessionId":{"type":"string"},"userId":{"type":"string","description":"Hashed pseudonym"},"path":{"type":"string"},"referrer":{"type":"string"},"properties":{"type":"object","additionalProperties":true}}},"TopSearch":{"type":"object","required":["query","count","sessions","avgResultCount","zeroResultRate"],"properties":{"query":{"type":"string"},"count":{"type":"integer"},"sessions":{"type":"integer"},"avgResultCount":{"type":"integer"},"zeroResultRate":{"type":"integer","description":"Percent of runs returning no results"}}},"FeedbackStats":{"type":"object","required":["total","trend","timeSeries","withAttachments","attachmentRate"],"properties":{"total":{"type":"integer"},"trend":{"type":"integer","description":"Percent change vs prior window"},"timeSeries":{"type":"array","items":{"type":"object","required":["timestamp","date","value"],"properties":{"timestamp":{"type":"integer"},"date":{"type":"string"},"value":{"type":"integer"}}}},"withAttachments":{"type":"integer"},"attachmentRate":{"type":"integer"}}},"UserActivityStats":{"type":"object","required":["totalPageViews","totalSessions","sparklineData","topPages"],"properties":{"totalPageViews":{"type":"integer"},"totalSessions":{"type":"integer"},"sparklineData":{"type":"array","items":{"type":"integer"}},"topPages":{"type":"array","items":{"type":"object","required":["path","count"],"properties":{"path":{"type":"string"},"count":{"type":"integer"}}}}}},"StudioQuerySpec":{"type":"object","properties":{"source":{"type":"string","enum":["analytics"],"description":"Always \"analytics\"."},"namespace":{"type":"string","description":"Which app/tenant to query. Must be one of the namespaces listed as available to you in the system prompt."},"eventName":{"type":"string","description":"Optional: restrict to a single event name (e.g. \"page_view\", \"ai_chat\"). Omit to include all events."},"filters":{"type":"array","description":"Optional: up to 10 equality filters, all of which must match (AND).","items":{"type":"object","properties":{"field":{"type":"string","description":"One of: path, referrer, name, or properties.<key> (e.g. \"properties.tier\")."},"op":{"type":"string","enum":["eq","neq","in"],"description":"\"eq\"/\"neq\" compare to a single string value; \"in\" matches any value in an array."},"value":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"A string for \"eq\"/\"neq\"; an array of strings for \"in\"."}},"required":["field","op","value"],"additionalProperties":false}},"groupBy":{"type":"object","description":"Optional: break the measure down by one dimension. Omit for a single total (big number).","properties":{"dimension":{"type":"string","description":"One of: path, referrer, name, time, or properties.<key>. Use \"time\" for a trend across the window."},"timeBucket":{"type":"string","enum":["hour","day","week"],"description":"Only with dimension \"time\": the bucket width. Defaults to \"day\"."}},"required":["dimension"],"additionalProperties":false},"series":{"type":"object","description":"Optional: split the measure into multiple series by a SECOND categorical dimension — e.g. groupBy \"time\" + series by \"name\" draws one line per event type; groupBy a category + series draws grouped bars. Requires groupBy and must differ from it. Use only when comparing a handful of categories across the primary axis.","properties":{"dimension":{"type":"string","description":"One of: path, referrer, name, or properties.<key>. NOT \"time\" — time is the primary axis."},"limit":{"type":"number","description":"Optional: keep only the top-N series by measure (default 6, max 8)."}},"required":["dimension"],"additionalProperties":false},"measure":{"type":"object","description":"What to compute over the matched events.","properties":{"fn":{"type":"string","enum":["count","sessions","users","anonymous","sum","avg","p50","p95"],"description":"count = number of events; sessions/users/anonymous = distinct counts; sum/avg/p50/p95 = numeric statistics over a property field."},"field":{"type":"string","description":"Required for sum/avg/p50/p95: a properties.<key> holding a number (e.g. \"properties.estimatedCostUsd\"). Omit for count/sessions/users/anonymous."}},"required":["fn"],"additionalProperties":false},"range":{"description":"The time window. Either a trailing number of days, or absolute since/until in epoch milliseconds. Capped server-side at 90 days.","anyOf":[{"type":"object","properties":{"days":{"type":"number","description":"Trailing window length in days (1–90)."}},"required":["days"],"additionalProperties":false},{"type":"object","properties":{"since":{"type":"number","description":"Window start, epoch milliseconds."},"until":{"type":"number","description":"Window end, epoch milliseconds. Defaults to now."}},"required":["since"],"additionalProperties":false}]},"limit":{"type":"number","description":"Optional: max rows for a categorical breakdown (1–100, default 50). Ignored for a time series, which is always returned whole."},"kind":{"type":"string","enum":["aggregate","experiment"],"description":"The query type. Omit or \"aggregate\" for the normal measure/groupBy analytics above. \"experiment\" instead measures an A/B experiment: it correlates flag exposures with a later outcome event to report per-variant conversion — set flagKey + outcomeEvent (and optionally exposureEvent) plus a range; measure/groupBy/series/filters/limit do not apply."},"flagKey":{"type":"string","description":"Experiment kind only: the experiment flag key whose variants to measure (matched against exposure events' properties.flag)."},"outcomeEvent":{"type":"string","description":"Experiment kind only: the event name that counts as a conversion (e.g. \"checkout_complete\", \"signup\"). A variant converts when an exposed identity emits this event at or after its first exposure."},"exposureEvent":{"type":"string","description":"Experiment kind only, optional: the exposure event name. Defaults to \"experiment_exposure\" (what the flag client emits on first variant read)."}},"required":["source","namespace","measure","range"],"additionalProperties":false},"StudioChartRef":{"type":"object","properties":{"kind":{"type":"string","enum":["stat","area","line","bar","column","table","multiLine","groupedBar","stackedBar","stackedArea"]},"title":{"type":"string"},"spec":{"type":"object","properties":{"source":{"type":"string","enum":["analytics"],"description":"Always \"analytics\"."},"namespace":{"type":"string","description":"Which app/tenant to query. Must be one of the namespaces listed as available to you in the system prompt."},"eventName":{"type":"string","description":"Optional: restrict to a single event name (e.g. \"page_view\", \"ai_chat\"). Omit to include all events."},"filters":{"type":"array","description":"Optional: up to 10 equality filters, all of which must match (AND).","items":{"type":"object","properties":{"field":{"type":"string","description":"One of: path, referrer, name, or properties.<key> (e.g. \"properties.tier\")."},"op":{"type":"string","enum":["eq","neq","in"],"description":"\"eq\"/\"neq\" compare to a single string value; \"in\" matches any value in an array."},"value":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"A string for \"eq\"/\"neq\"; an array of strings for \"in\"."}},"required":["field","op","value"],"additionalProperties":false}},"groupBy":{"type":"object","description":"Optional: break the measure down by one dimension. Omit for a single total (big number).","properties":{"dimension":{"type":"string","description":"One of: path, referrer, name, time, or properties.<key>. Use \"time\" for a trend across the window."},"timeBucket":{"type":"string","enum":["hour","day","week"],"description":"Only with dimension \"time\": the bucket width. Defaults to \"day\"."}},"required":["dimension"],"additionalProperties":false},"series":{"type":"object","description":"Optional: split the measure into multiple series by a SECOND categorical dimension — e.g. groupBy \"time\" + series by \"name\" draws one line per event type; groupBy a category + series draws grouped bars. Requires groupBy and must differ from it. Use only when comparing a handful of categories across the primary axis.","properties":{"dimension":{"type":"string","description":"One of: path, referrer, name, or properties.<key>. NOT \"time\" — time is the primary axis."},"limit":{"type":"number","description":"Optional: keep only the top-N series by measure (default 6, max 8)."}},"required":["dimension"],"additionalProperties":false},"measure":{"type":"object","description":"What to compute over the matched events.","properties":{"fn":{"type":"string","enum":["count","sessions","users","anonymous","sum","avg","p50","p95"],"description":"count = number of events; sessions/users/anonymous = distinct counts; sum/avg/p50/p95 = numeric statistics over a property field."},"field":{"type":"string","description":"Required for sum/avg/p50/p95: a properties.<key> holding a number (e.g. \"properties.estimatedCostUsd\"). Omit for count/sessions/users/anonymous."}},"required":["fn"],"additionalProperties":false},"range":{"description":"The time window. Either a trailing number of days, or absolute since/until in epoch milliseconds. Capped server-side at 90 days.","anyOf":[{"type":"object","properties":{"days":{"type":"number","description":"Trailing window length in days (1–90)."}},"required":["days"],"additionalProperties":false},{"type":"object","properties":{"since":{"type":"number","description":"Window start, epoch milliseconds."},"until":{"type":"number","description":"Window end, epoch milliseconds. Defaults to now."}},"required":["since"],"additionalProperties":false}]},"limit":{"type":"number","description":"Optional: max rows for a categorical breakdown (1–100, default 50). Ignored for a time series, which is always returned whole."},"kind":{"type":"string","enum":["aggregate","experiment"],"description":"The query type. Omit or \"aggregate\" for the normal measure/groupBy analytics above. \"experiment\" instead measures an A/B experiment: it correlates flag exposures with a later outcome event to report per-variant conversion — set flagKey + outcomeEvent (and optionally exposureEvent) plus a range; measure/groupBy/series/filters/limit do not apply."},"flagKey":{"type":"string","description":"Experiment kind only: the experiment flag key whose variants to measure (matched against exposure events' properties.flag)."},"outcomeEvent":{"type":"string","description":"Experiment kind only: the event name that counts as a conversion (e.g. \"checkout_complete\", \"signup\"). A variant converts when an exposed identity emits this event at or after its first exposure."},"exposureEvent":{"type":"string","description":"Experiment kind only, optional: the exposure event name. Defaults to \"experiment_exposure\" (what the flag client emits on first variant read)."}},"required":["source","namespace","measure","range"],"additionalProperties":false},"window":{"type":"object","description":"Generation-time snapshot of the resolved window. Stored, but not authoritative: `spec.range` decides the span a chart shows, so a relative `{days}` range slides forward on every load while this stays pinned. Send the window the spec resolves to now.","properties":{"since":{"type":"integer"},"until":{"type":"integer"}},"required":["since","until"]},"targetSlug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Optional kebab-case app slug this widget targets (cross-app dashboards)."}},"required":["kind","title","spec","window"],"additionalProperties":false},"StudioQueryResult":{"type":"object","required":["rows","rowCount","window","spec"],"properties":{"rows":{"type":"array","description":"Single-dimension aggregation: one row per group (or a single total when there is no groupBy).","items":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string","description":"Group value — a path/referrer/name, or the ISO date for a time bucket."},"bucket":{"type":"integer","description":"Bucket start (epoch ms) when grouping by time; absent otherwise."},"value":{"type":"number"}}}},"pivot":{"type":"object","description":"Present only when the spec carries a `series` split — the multi-series breakdown.","required":["seriesNames","rows"],"properties":{"seriesNames":{"type":"array","items":{"type":"string"}},"rows":{"type":"array","items":{"type":"object","required":["key","values"],"properties":{"key":{"type":"string"},"bucket":{"type":"integer"},"values":{"type":"array","items":{"type":"number"},"description":"Aligned with seriesNames."}}}}}},"rowCount":{"type":"integer"},"window":{"type":"object","required":["since","until"],"properties":{"since":{"type":"integer"},"until":{"type":"integer"}}},"spec":{"$ref":"#/components/schemas/StudioQuerySpec"}}},"StudioDashboard":{"type":"object","required":["id","name","charts","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"charts":{"type":"array","items":{"$ref":"#/components/schemas/StudioChartRef"}},"createdAt":{"type":"integer","description":"Epoch ms"},"updatedAt":{"type":"integer","description":"Epoch ms"}}},"MarozzoSource":{"type":"object","required":["title","url"],"properties":{"title":{"type":"string"},"url":{"type":"string"},"snippet":{"type":"string"}}},"MarozzoChatResult":{"oneOf":[{"type":"object","required":["threadId","message","sources","truncated"],"properties":{"threadId":{"type":"string"},"message":{"type":"string"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/MarozzoSource"}},"truncated":{"type":"boolean"}}},{"type":"object","required":["refused"],"properties":{"refused":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string"}}}}}]},"MarozzoMessage":{"type":"object","required":["id","role","content","createdAt"],"properties":{"id":{"type":"string"},"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"},"createdAt":{"type":"integer"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/MarozzoSource"}}}},"MarozzoThreadHistory":{"type":"object","required":["thread","messages"],"properties":{"thread":{"type":"object","required":["id","createdAt"],"properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"takeaways":{"type":"array","items":{"type":"string"}}}},"messages":{"type":"array","items":{"$ref":"#/components/schemas/MarozzoMessage"}}}},"DictionaryHit":{"type":"object","required":["source","headword","score","snippet","citation"],"properties":{"source":{"type":"string","enum":["florio","crusca"]},"headword":{"type":"string"},"score":{"type":"number"},"snippet":{"type":"string"},"citation":{"type":"string"}}},"TreatiseHit":{"type":"object","required":["source","book","chapter","title","score","snippet","citation"],"properties":{"source":{"type":"string","enum":["manciolino","opera_nova","dall_agocchie"]},"book":{"type":"integer"},"chapter":{"type":"integer"},"title":{"type":"string"},"score":{"type":"number"},"snippet":{"type":"string"},"citation":{"type":"string"}}},"HeroPromo":{"type":"object","required":["id","badge","message","ctaLabel","ctaHref","enabled","order","startsAt","endsAt","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"badge":{"type":"string"},"message":{"type":"string"},"ctaLabel":{"type":"string"},"ctaHref":{"type":"string"},"enabled":{"type":"boolean"},"order":{"type":"integer"},"startsAt":{"type":["integer","null"]},"endsAt":{"type":["integer","null"]},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}}},"HeroPromoInput":{"type":"object","required":["badge","message","ctaHref","enabled"],"properties":{"badge":{"type":"string"},"message":{"type":"string"},"ctaLabel":{"type":"string","description":"Empty string makes the whole pill clickable"},"ctaHref":{"type":"string","description":"Internal path (starts with /) or external URL"},"enabled":{"type":"boolean"},"startsAt":{"type":["integer","null"],"description":"Epoch ms, or null for no lower bound"},"endsAt":{"type":["integer","null"],"description":"Epoch ms, or null for no upper bound"}}},"ImageVariant":{"type":"object","required":["storageKey","width","height","size","mimeType"],"properties":{"storageKey":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"mimeType":{"type":"string"}}},"MediaAsset":{"type":"object","required":["_id","type","mimeType","originalName","size","visibility","processingStatus","createdAt"],"properties":{"_id":{"type":"string"},"type":{"type":"string","enum":["image","file"]},"mimeType":{"type":"string"},"originalName":{"type":"string"},"displayName":{"type":"string"},"storageKey":{"type":"string"},"sourceStorageKey":{"type":"string"},"imageVariantVersion":{"type":"integer"},"imageVariants":{"type":"object","properties":{"thumb":{"$ref":"#/components/schemas/ImageVariant"},"card":{"$ref":"#/components/schemas/ImageVariant"},"hero":{"$ref":"#/components/schemas/ImageVariant"},"full":{"$ref":"#/components/schemas/ImageVariant"},"square":{"$ref":"#/components/schemas/ImageVariant"}}},"size":{"type":"integer"},"tags":{"type":"array","items":{"type":"string"}},"visibility":{"type":"string","enum":["public","protected"]},"allowedNamespaces":{"type":"array","items":{"type":"string"},"description":"PROTECTED-only namespace allowlist for the signed-URL mint gate. Absent for public assets."},"processingStatus":{"type":"string","enum":["pending","processing","ready","failed"]},"blurhash":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"uploadedBy":{"type":"string"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}}},"VideoAsset":{"type":"object","required":["_id","bunnyVideoId","bunnyLibraryId","title","visibility","createdAt"],"properties":{"_id":{"type":"string"},"bunnyVideoId":{"type":"string"},"bunnyLibraryId":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"visibility":{"type":"string","enum":["public","protected"]},"allowedNamespaces":{"type":"array","items":{"type":"string"},"description":"PROTECTED-only namespace allowlist for the signed-URL mint gate. Absent for public videos."},"duration":{"type":"number"},"thumbnailUrl":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"uploadStatus":{"type":"string","enum":["uploading","processing","ready","failed"]},"uploadedBy":{"type":"string"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}}},"Note":{"type":"object","required":["id","title","encryptedContent","iv","salt","tags","archived","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"encryptedContent":{"type":"string","description":"base64 AES-GCM ciphertext (opaque to the server)"},"iv":{"type":"string","description":"base64 initialization vector"},"salt":{"type":"string","description":"base64 key-derivation salt"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"archived":{"type":"boolean"},"createdAt":{"type":"integer","description":"Epoch ms"},"updatedAt":{"type":"integer","description":"Epoch ms"},"lastOpenedAt":{"type":"integer","description":"Epoch ms"},"frecencyScore":{"type":"number"},"boostedUntil":{"type":"integer","description":"Epoch ms — pinned while > now"}}},"NoteTitle":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string"},"title":{"type":"string"}}},"PatListEntry":{"type":"object","required":["hash","label","createdAt"],"properties":{"hash":{"type":"string","description":"SHA-256 fingerprint of the token (not the secret)."},"label":{"type":"string"},"createdAt":{"type":"integer"},"lastUsedAt":{"type":"integer"},"revokedAt":{"type":"integer"},"scope":{"$ref":"#/components/schemas/PatScope"}}},"WorkflowDefinition":{"oneOf":[{"type":"object","required":["schemaVersion","workflowKey","startNodeId","nodes"],"properties":{"schemaVersion":{"const":1},"workflowKey":{"type":"string"},"startNodeId":{"type":"string"},"nodes":{"type":"array","minItems":1,"maxItems":64,"items":{"oneOf":[{"type":"object","required":["id","kind","executorKey","executorVersion","config","input"],"properties":{"id":{"type":"string"},"kind":{"const":"task"},"executorVersion":{"const":1},"input":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]},"nextNodeId":{"type":"string"},"retry":{"type":"object","required":["maxAttempts","initialBackoffMs"],"properties":{"maxAttempts":{"type":"integer","minimum":1,"maximum":10},"initialBackoffMs":{"type":"integer","minimum":1,"maximum":60000},"base":{"type":"number","minimum":1,"maximum":10,"default":2}},"additionalProperties":false},"executorKey":{"const":"artifact.identity"},"config":{"type":"object","additionalProperties":false}},"additionalProperties":false},{"type":"object","required":["id","kind","executorKey","executorVersion","config","input"],"properties":{"id":{"type":"string"},"kind":{"const":"task"},"executorVersion":{"const":1},"input":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]},"nextNodeId":{"type":"string"},"retry":{"type":"object","required":["maxAttempts","initialBackoffMs"],"properties":{"maxAttempts":{"type":"integer","minimum":1,"maximum":10},"initialBackoffMs":{"type":"integer","minimum":1,"maximum":60000},"base":{"type":"number","minimum":1,"maximum":10,"default":2}},"additionalProperties":false},"executorKey":{"const":"artifact.append"},"config":{"type":"object","required":["suffix"],"properties":{"suffix":{"type":"string"}},"additionalProperties":false}},"additionalProperties":false},{"type":"object","required":["id","kind","childNodeIds","nextNodeId"],"properties":{"id":{"type":"string"},"kind":{"const":"parallel"},"childNodeIds":{"type":"array","minItems":2,"maxItems":16,"items":{"type":"string"}},"nextNodeId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["id","kind","input","equalsArtifactId","whenTrueNodeId","whenFalseNodeId"],"properties":{"id":{"type":"string"},"kind":{"const":"branch"},"input":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]},"equalsArtifactId":{"type":"string"},"whenTrueNodeId":{"type":"string"},"whenFalseNodeId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["id","kind","eventName","nextNodeId"],"properties":{"id":{"type":"string"},"kind":{"const":"wait"},"eventName":{"type":"string"},"nextNodeId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["id","kind","input"],"properties":{"id":{"type":"string"},"kind":{"const":"output"},"input":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]}},"additionalProperties":false}]}}},"additionalProperties":false},{"type":"object","required":["schemaVersion","workflowKey","startNodeId","nodes"],"properties":{"schemaVersion":{"const":2},"workflowKey":{"type":"string"},"startNodeId":{"type":"string"},"nodes":{"type":"array","minItems":1,"maxItems":64,"items":{"oneOf":[{"type":"object","required":["id","kind","executorKey","executorVersion","config","inputs"],"properties":{"id":{"type":"string"},"kind":{"const":"task"},"inputs":{"type":"array","minItems":1,"maxItems":4,"items":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]}},"nextNodeId":{"type":"string"},"retry":{"type":"object","required":["maxAttempts","initialBackoffMs"],"properties":{"maxAttempts":{"type":"integer","minimum":1,"maximum":10},"initialBackoffMs":{"type":"integer","minimum":1,"maximum":60000},"base":{"type":"number","minimum":1,"maximum":10,"default":2}},"additionalProperties":false},"executorKey":{"const":"artifact.identity"},"executorVersion":{"const":1},"config":{"type":"object","additionalProperties":false}},"additionalProperties":false},{"type":"object","required":["id","kind","executorKey","executorVersion","config","inputs"],"properties":{"id":{"type":"string"},"kind":{"const":"task"},"inputs":{"type":"array","minItems":1,"maxItems":4,"items":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]}},"nextNodeId":{"type":"string"},"retry":{"type":"object","required":["maxAttempts","initialBackoffMs"],"properties":{"maxAttempts":{"type":"integer","minimum":1,"maximum":10},"initialBackoffMs":{"type":"integer","minimum":1,"maximum":60000},"base":{"type":"number","minimum":1,"maximum":10,"default":2}},"additionalProperties":false},"executorKey":{"const":"artifact.append"},"executorVersion":{"const":1},"config":{"type":"object","required":["suffix"],"properties":{"suffix":{"type":"string"}},"additionalProperties":false}},"additionalProperties":false},{"type":"object","required":["id","kind","executorKey","executorVersion","config","inputs"],"properties":{"id":{"type":"string"},"kind":{"const":"task"},"inputs":{"type":"array","minItems":1,"maxItems":4,"items":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]}},"nextNodeId":{"type":"string"},"retry":{"type":"object","required":["maxAttempts","initialBackoffMs"],"properties":{"maxAttempts":{"type":"integer","minimum":1,"maximum":10},"initialBackoffMs":{"type":"integer","minimum":1,"maximum":60000},"base":{"type":"number","minimum":1,"maximum":10,"default":2}},"additionalProperties":false},"executorKey":{"const":"sdl.validate"},"executorVersion":{"const":2},"config":{"type":"object","additionalProperties":false}},"additionalProperties":false},{"type":"object","required":["id","kind","childNodeIds","nextNodeId"],"properties":{"id":{"type":"string"},"kind":{"const":"parallel"},"childNodeIds":{"type":"array","minItems":2,"maxItems":16,"items":{"type":"string"}},"nextNodeId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["id","kind","input","condition","whenTrueNodeId","whenFalseNodeId"],"properties":{"id":{"type":"string"},"kind":{"const":"branch"},"input":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]},"condition":{"oneOf":[{"type":"object","required":["kind","equalsArtifactId"],"properties":{"kind":{"const":"artifact.equals"},"equalsArtifactId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["kind","acceptStatuses"],"properties":{"kind":{"const":"sdl.validationStatus"},"acceptStatuses":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"string","enum":["accepted","accepted_with_warnings","rejected"]}}},"additionalProperties":false}]},"whenTrueNodeId":{"type":"string"},"whenFalseNodeId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["id","kind","eventName","nextNodeId"],"properties":{"id":{"type":"string"},"kind":{"const":"wait"},"eventName":{"type":"string"},"nextNodeId":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["id","kind","input"],"properties":{"id":{"type":"string"},"kind":{"const":"output"},"input":{"oneOf":[{"type":"object","required":["source"],"properties":{"source":{"const":"initial"}},"additionalProperties":false},{"type":"object","required":["source","nodeId"],"properties":{"source":{"const":"node"},"nodeId":{"type":"string"}},"additionalProperties":false}]}},"additionalProperties":false}]}}},"additionalProperties":false}]},"WorkflowDefinitionSummary":{"type":"object","required":["_id","_creationTime","namespace","workflowKey","retentionDays","latestRevision","createdBy","createdAt","updatedBy","updatedAt"],"properties":{"_id":{"type":"string"},"_creationTime":{"type":"number"},"namespace":{"type":"string"},"workflowKey":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"retentionDays":{"type":"integer","minimum":1,"maximum":365},"latestRevision":{"type":"integer","minimum":1},"latestRevisionId":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"number","description":"Epoch ms"},"updatedBy":{"type":"string"},"updatedAt":{"type":"number","description":"Epoch ms"}}},"WorkflowDefinitionRevision":{"type":"object","required":["_id","_creationTime","definitionId","namespace","workflowKey","revision","runtimeVersion","definition","createdBy","createdAt"],"properties":{"_id":{"type":"string"},"_creationTime":{"type":"number"},"definitionId":{"type":"string"},"namespace":{"type":"string"},"workflowKey":{"type":"string"},"revision":{"type":"integer","minimum":1},"runtimeVersion":{"const":1},"definition":{"$ref":"#/components/schemas/WorkflowDefinition"},"createdBy":{"type":"string"},"createdAt":{"type":"number","description":"Epoch ms"}}},"WorkflowRun":{"type":"object","required":["_id","_creationTime","namespace","workflowKey","definitionId","revisionId","revision","runtimeVersion","status","executionEpoch","createdBy","createdAt","updatedAt","retentionDays"],"properties":{"_id":{"type":"string"},"_creationTime":{"type":"number"},"namespace":{"type":"string"},"workflowKey":{"type":"string"},"definitionId":{"type":"string"},"revisionId":{"type":"string"},"revision":{"type":"integer","minimum":1},"runtimeVersion":{"const":1},"status":{"type":"string","enum":["queued","running","waiting","completed","failed","canceled"]},"executionEpoch":{"type":"integer","minimum":1},"initialArtifactId":{"type":"string"},"outputArtifactId":{"type":"string"},"waitingNodeId":{"type":"string"},"waitingEventName":{"type":"string"},"errorMessage":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"number","description":"Epoch ms"},"startedAt":{"type":"number","description":"Epoch ms"},"updatedAt":{"type":"number","description":"Epoch ms"},"terminalAt":{"type":"number","description":"Epoch ms"},"retentionDays":{"type":"integer","minimum":1,"maximum":365},"retentionExpiresAt":{"type":"number","description":"Epoch ms"}}},"WorkflowRunEvent":{"type":"object","required":["_id","_creationTime","namespace","runId","executionEpoch","sequence","type","createdBy","createdAt"],"properties":{"_id":{"type":"string"},"_creationTime":{"type":"number"},"namespace":{"type":"string"},"runId":{"type":"string"},"executionEpoch":{"type":"integer","minimum":1},"sequence":{"type":"integer","minimum":1},"type":{"type":"string","enum":["run_queued","run_started","run_waiting","run_restarted","run_cancel_requested","run_canceled","run_completed","run_failed","parallel_started","parallel_completed","branch_selected","wait_started","wait_completed","node_started","node_completed","node_failed","node_completion_ignored","external_event_sent","output_completed"]},"nodeId":{"type":"string"},"artifactId":{"type":"string"},"eventName":{"type":"string"},"nextNodeId":{"type":"string"},"errorMessage":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"number","description":"Epoch ms"}}},"WorkflowArtifact":{"type":"object","required":["_id","_creationTime","namespace","runId","revisionId","executionEpoch","kind","contentType","sizeBytes","createdBy","createdAt"],"properties":{"_id":{"type":"string"},"_creationTime":{"type":"number"},"namespace":{"type":"string"},"runId":{"type":"string"},"revisionId":{"type":"string"},"executionEpoch":{"type":"integer","minimum":1},"kind":{"type":"string","enum":["initial","node_output","event_input","node_report","node_document","media_evidence"]},"nodeId":{"type":"string"},"parentArtifactId":{"type":"string"},"contentType":{"type":"string"},"sizeBytes":{"type":"integer","minimum":0,"maximum":262144},"createdBy":{"type":"string"},"createdAt":{"type":"number","description":"Epoch ms"}}},"WorkflowArtifactSummary":{"type":"object","required":["_id","kind","contentType","createdAt"],"properties":{"_id":{"type":"string"},"kind":{"type":"string","enum":["initial","node_output","event_input","node_report","node_document","media_evidence"]},"contentType":{"type":"string"},"nodeId":{"type":"string"},"createdAt":{"type":"number","description":"Epoch ms"}}},"WorkflowArtifactResult":{"type":"object","required":["artifact","text"],"properties":{"artifact":{"$ref":"#/components/schemas/WorkflowArtifact"},"text":{"type":"string","description":"Full core-bounded text payload (maximum 256 KiB UTF-8)."}}},"WorkflowTextArtifactInput":{"type":"object","required":["contentType","text"],"properties":{"contentType":{"type":"string","description":"MIME type for the immutable text payload."},"text":{"type":"string","description":"Immutable UTF-8 text payload. Size is bounded by the control plane."}}}}},"paths":{"/api/v1/auth/whoami":{"get":{"tags":["system"],"summary":"Resolve the active token","description":"Returns the user the active Bearer token resolves to (or `kind: 'service'` for the platform key). Available even without `api:read` so callers can discover what their token is and why they may be locked out.","operationId":"get_auth_whoami","responses":{"200":{"description":"Token resolved","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CallerInfo"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":[]},{"oauth2":["full"]}]}},"/api/v1/auth/token":{"delete":{"tags":["system"],"summary":"Revoke the calling Personal Access Token","description":"Revokes the PAT used to authenticate this request. The service key cannot be revoked through this endpoint.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_auth_token","responses":{"200":{"description":"Token revoked","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["revoked"],"properties":{"revoked":{"const":true}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/me":{"get":{"tags":["me"],"summary":"Get my account","description":"Consolidated view of your own account: identity, display profile, marketing consent, notification preferences, and subscription summary. Ownership-only — always the account the bearer token resolves to.","operationId":"get_me","responses":{"200":{"description":"Account bundle","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MeBundle"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/me/profile":{"patch":{"tags":["me"],"summary":"Update my profile","description":"Update your own display name and/or avatar URL. Pass `avatarUrl: null` to remove the avatar. Display-name changes propagate to content attribution in the background.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_me_profile","responses":{"200":{"description":"Updated profile","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"profile":{"type":"object","additionalProperties":true}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"avatarUrl":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/me/notification-prefs":{"get":{"tags":["me"],"summary":"Get my notification preferences","description":"Get my notification preferences","operationId":"get_me_notification_prefs","responses":{"200":{"description":"Preference map","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MeNotificationPrefs"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["me"],"summary":"Set a notification preference","description":"Enable or disable one suppressible notification type for yourself. Unknown types are rejected.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_me_notification_prefs","responses":{"200":{"description":"Updated preference map","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MeNotificationPrefs"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","enabled"],"properties":{"type":{"type":"string"},"enabled":{"type":"boolean"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/me/ai-prefs":{"get":{"tags":["me"],"summary":"Get my AI feature preferences","description":"Get my AI feature preferences","operationId":"get_me_ai_prefs","responses":{"200":{"description":"Preference map","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MeAiPrefs"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["me"],"summary":"Set an AI feature preference","description":"Turn one catalogued generative-AI feature on or off for yourself. Features outside the catalog are mandatory and are rejected.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_me_ai_prefs","responses":{"200":{"description":"Updated preference map","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MeAiPrefs"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["feature","enabled"],"properties":{"feature":{"type":"string"},"enabled":{"type":"boolean"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/me/ai-features":{"get":{"tags":["me"],"summary":"Get my AI feature availability","description":"Composed availability per feature: plan entitlement AND your preference AND remaining budget, with the reason for any denial.","operationId":"get_me_ai_features","responses":{"200":{"description":"Availability per feature","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MeAiFeatures"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"app","in":"query","required":false,"schema":{"type":"string"},"description":"App namespace, for app-scoped entitlements."}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/me/email-consents":{"get":{"tags":["me"],"summary":"Get my per-app email consents","description":"Your marketing email consent for every app that sends updates, one row per app with its display name and subscriber status.","operationId":"get_me_email_consents","responses":{"200":{"description":"Consent rows","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MeEmailConsent"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/me/email-consent":{"patch":{"tags":["me"],"summary":"Set my marketing email consent","description":"Pass `namespace` to set consent for one app (each app sends its own updates); omitting it sets the deprecated account-wide flag.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_me_email_consent","responses":{"200":{"description":"Updated consent","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["emailSubscribed"],"properties":{"emailSubscribed":{"type":"boolean"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emailSubscribed"],"properties":{"emailSubscribed":{"type":"boolean"},"namespace":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/me/permissions":{"get":{"tags":["me"],"summary":"Get my permissions in a namespace","description":"Your own RBAC bundle in the given app namespace. A PAT scope may narrow what the token can actually do below what the bundle grants; `GET /api/v1/auth/whoami` reports the scope.","operationId":"get_me_permissions","responses":{"200":{"description":"Permission bundle","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MePermissionBundle"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/me/sessions":{"get":{"tags":["me"],"summary":"List my sessions","description":"Your own auth sessions (creation and expiry), newest first. Read-only.","operationId":"get_me_sessions","responses":{"200":{"description":"Sessions","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MeSession"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/tasks":{"get":{"tags":["tasks"],"summary":"List tasks","description":"Compatibility alias for caller-owned Kvark tasks. Defaults to the default board. Uses opaque, filter-bound keyset cursors; exact totals are intentionally omitted. If tasks change between pages, restart without a cursor.","operationId":"get_tasks","responses":{"200":{"description":"Page of tasks","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"meta":{"type":"object","required":["hasMore","nextCursor"],"properties":{"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"query","description":"Board to list. Omit for the default board.","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["todo","in_progress","done"]}},{"name":"tags","in":"query","description":"Comma-separated tag list — tasks must match all","schema":{"type":"string"}},{"name":"archived","in":"query","schema":{"type":"boolean"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/tasks/{id}":{"get":{"tags":["tasks"],"summary":"Get a task by id","description":"Get a task by id","operationId":"get_tasks_by_id","responses":{"200":{"description":"Task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Task"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/tasks/{id}/attachments/{index}":{"get":{"tags":["tasks"],"summary":"Task attachment compatibility boundary","description":"Attachments are not available through the Task List compatibility API because Kvark and Task List task IDs are not interchangeable. Open the original task in Task List to access its attachments.","operationId":"get_tasks_by_id_attachments_by_index","responses":{"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Attachments are not available through the Task List compatibility API because Kvark and Task List task IDs are not interchangeable. Open the original task in Task List to access its attachments."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","minimum":0}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/tasks/{id}/move":{"patch":{"tags":["tasks"],"summary":"Move a task to a different status column","description":"Updates a task to todo, in_progress, or done. Places it at the end of the destination column.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_tasks_by_id_move","responses":{"200":{"description":"Updated task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Task"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["todo","in_progress","done"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/tasks/boards":{"get":{"tags":["tasks"],"summary":"List boards","description":"List caller-owned Kvark Boards, including the default Board, each with the caller’s owner role.","operationId":"get_tasks_boards","responses":{"200":{"description":"Boards with the caller’s role","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BoardSummary"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["tasks"],"summary":"Create a board","description":"Create a new board owned by the caller. Requires a user-bound PAT.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_tasks_boards","responses":{"201":{"description":"Created board","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Board"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/tasks/boards/{boardId}":{"patch":{"tags":["tasks"],"summary":"Rename a board","description":"Rename a board the caller owns. The default board cannot be renamed.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_tasks_boards_by_boardId","responses":{"200":{"description":"Renamed board","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Board"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["tasks"],"summary":"Archive a board","description":"Archive a caller-owned Kvark Board while preserving its tasks and structure. The default Board cannot be archived.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_tasks_boards_by_boardId","responses":{"200":{"description":"Deletion result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/tasks/boards/{boardId}/shares":{"get":{"tags":["tasks"],"summary":"Board sharing compatibility boundary","description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing.","operationId":"get_tasks_boards_by_boardId_shares","responses":{"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["tasks"],"summary":"Board sharing compatibility boundary","description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_tasks_boards_by_boardId_shares","responses":{"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","role"],"properties":{"email":{"type":"string"},"role":{"type":"string","enum":["viewer","editor"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/tasks/boards/{boardId}/shares/{granteeSubject}":{"delete":{"tags":["tasks"],"summary":"Board sharing compatibility boundary","description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_tasks_boards_by_boardId_shares_by_granteeSubject","responses":{"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"granteeSubject","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/tasks/boards/{boardId}/leave":{"post":{"tags":["tasks"],"summary":"Board sharing compatibility boundary","description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_tasks_boards_by_boardId_leave","responses":{"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Board sharing is not available through the Task List compatibility API because Kvark and Task List Board IDs are not interchangeable. Open the original Board in Task List to manage sharing."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/tasks":{"get":{"tags":["kvark"],"summary":"List Kvark tasks","description":"Caller-owned canonical task aggregates. Zero-knowledge bodies are omitted. Uses opaque, filter-bound keyset cursors; exact totals are intentionally omitted. If tasks change between pages, restart without a cursor.","operationId":"get_kvark_tasks","responses":{"200":{"description":"Paginated task list","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KvarkAutomationTask"}},"meta":{"type":"object","required":["hasMore","nextCursor"],"properties":{"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"boardId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["todo","in_progress","done"]}},{"name":"tags","in":"query","description":"Comma-separated; all tags must match.","schema":{"type":"string"}},{"name":"archived","in":"query","schema":{"type":"boolean"}},{"name":"dueBefore","in":"query","schema":{"type":"integer","minimum":0}},{"name":"dueAfter","in":"query","schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["kvark"],"summary":"Create a Kvark task","description":"Creates canonical identity, Action, and Placement records. Plaintext bodies require server-readable visibility.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_tasks","responses":{"201":{"description":"Created task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"visibility":{"type":"string","enum":["zero-knowledge","server-readable"]},"body":{"type":"string","description":"Plaintext body. Accepted only when the task is server-readable."},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"boardId":{"type":"string"},"status":{"type":"string","enum":["todo","in_progress","done"]},"dueAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"reminder":{"type":"object","properties":{"remindAt":{"type":"integer","minimum":0},"recurrence":{"type":"string","enum":["daily","weekdays","weekly","monthly"]},"channel":{"type":"string","enum":["notification"]}},"required":["remindAt"]},"idempotencyKey":{"type":"string"}},"required":["title"]}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/tasks/{id}":{"get":{"tags":["kvark"],"summary":"Get a Kvark task","description":"Get a Kvark task","operationId":"get_kvark_tasks_by_id","responses":{"200":{"description":"Kvark task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["kvark"],"summary":"Update a Kvark task","description":"Update a Kvark task\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_kvark_tasks_by_id","responses":{"200":{"description":"Kvark task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"visibility":{"type":"string","enum":["zero-knowledge","server-readable"]},"body":{"type":"string","description":"Plaintext body. Accepted only when the task is server-readable."},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"boardId":{"type":"string"},"status":{"type":"string","enum":["todo","in_progress","done"]},"dueAt":{"type":"integer","minimum":0,"description":"Epoch milliseconds."},"reminder":{"type":"object","properties":{"remindAt":{"type":"integer","minimum":0},"recurrence":{"type":"string","enum":["daily","weekdays","weekly","monthly"]},"channel":{"type":"string","enum":["notification"]}},"required":["remindAt"]},"clearDueAt":{"type":"boolean"},"clearReminder":{"type":"boolean"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["kvark"],"summary":"Delete a Kvark task","description":"Delete a Kvark task\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_kvark_tasks_by_id","responses":{"200":{"description":"Deletion result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/tasks/{id}/move":{"patch":{"tags":["kvark"],"summary":"Move a Kvark task","description":"Move a Kvark task\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_kvark_tasks_by_id_move","responses":{"200":{"description":"Updated Kvark task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["todo","in_progress","done"]},"boardId":{"type":"string"},"afterTaskId":{"type":"string"},"beforeTaskId":{"type":"string"}},"required":["status"]}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/tasks/{id}/complete":{"post":{"tags":["kvark"],"summary":"Complete a Kvark task","description":"Complete a Kvark task\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_tasks_by_id_complete","responses":{"200":{"description":"Updated Kvark task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/tasks/{id}/archive":{"post":{"tags":["kvark"],"summary":"Archive a Kvark task","description":"Archive a Kvark task\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_tasks_by_id_archive","responses":{"200":{"description":"Updated Kvark task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/tasks/{id}/restore":{"post":{"tags":["kvark"],"summary":"Restore a Kvark task","description":"Restore a Kvark task\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_tasks_by_id_restore","responses":{"200":{"description":"Updated Kvark task","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkAutomationTask"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/task-tags":{"get":{"tags":["kvark"],"summary":"List Kvark task tags","description":"Scans one bounded page of active task projections. Follow nextCursor and union the pages; tags may repeat between pages. If tasks change between pages, restart without a cursor.","operationId":"get_kvark_task_tags","responses":{"200":{"description":"One bounded page of sorted task tags","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","required":["hasMore","nextCursor"],"properties":{"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"scanLimit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/kvark/task-index/backfill":{"post":{"tags":["kvark"],"summary":"Backfill the Kvark task projection index","description":"Processes one bounded, idempotent caller-owned batch. Repeat until complete before using task list automation.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_task_index_backfill","responses":{"200":{"description":"Backfill batch status","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["complete","processed","totalProcessed"],"properties":{"complete":{"type":"boolean"},"processed":{"type":"integer","minimum":0},"totalProcessed":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"batchSize":{"type":"integer","minimum":1,"maximum":50}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/boards":{"get":{"tags":["kvark"],"summary":"List Kvark boards","description":"List Kvark boards","operationId":"get_kvark_boards","responses":{"200":{"description":"Kvark Board response","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["kvark"],"summary":"Create a Kvark task board","description":"Create a Kvark task board\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_boards","responses":{"201":{"description":"Kvark Board response","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkBoard"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}},"required":["name"]}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/boards/{id}":{"patch":{"tags":["kvark"],"summary":"Update a Kvark board","description":"Update a Kvark board\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_kvark_boards_by_id","responses":{"200":{"description":"Kvark Board response","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/KvarkBoard"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["kvark"],"summary":"Archive a Kvark board","description":"Archive a Kvark board\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_kvark_boards_by_id","responses":{"200":{"description":"Kvark Board response","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/boards/{id}/columns":{"get":{"tags":["kvark"],"summary":"List Kvark Board columns","description":"List Kvark Board columns","operationId":"get_kvark_boards_by_id_columns","responses":{"200":{"description":"Board columns","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KvarkBoardColumn"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/kvark/boards/{id}/placements":{"get":{"tags":["kvark"],"summary":"List Kvark Board placements","description":"List Kvark Board placements","operationId":"get_kvark_boards_by_id_placements","responses":{"200":{"description":"Board placements","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KvarkBoardPlacement"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/kvark/write/capture_entry":{"post":{"tags":["kvark"],"summary":"Capture a Kvark entry with duplicate-safe delivery","description":"Capture one entry with duplicate-safe delivery. Private and sealed modes accept ciphertext only; server-readable mode explicitly stores plaintext for authorized automation. Reuse the capture ID and identical content when retrying. Owner must match the authenticated caller.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_write_capture_entry","responses":{"200":{"description":"Capture a Kvark entry with duplicate-safe delivery","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"captureId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ownerSubject":{"type":"string","minLength":1,"maxLength":256},"content":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"private"},"kind":{"type":"string","enum":["journal","canvas"]},"encryptedContent":{"type":"string","minLength":1,"maxLength":750000},"iv":{"type":"string","minLength":1,"maxLength":256},"dekEnvelope":{"type":"object","properties":{"version":{"type":"number","const":1},"wrappedDek":{"type":"string","minLength":1,"maxLength":4096},"wrapIv":{"type":"string","minLength":1,"maxLength":256}},"required":["version","wrappedDek","wrapIv"],"additionalProperties":false}},"required":["mode","kind","encryptedContent","iv","dekEnvelope"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"sealed"},"kind":{"type":"string","const":"journal"},"encryptedContent":{"type":"string","minLength":1,"maxLength":750000},"iv":{"type":"string","minLength":1,"maxLength":256},"sealedDek":{"type":"object","properties":{"ephX25519":{"type":"string","minLength":1,"maxLength":256},"mlkemCt":{"type":"string","minLength":1,"maxLength":4096},"iv":{"type":"string","minLength":1,"maxLength":256},"wrapped":{"type":"string","minLength":1,"maxLength":512}},"required":["ephX25519","mlkemCt","iv","wrapped"],"additionalProperties":false}},"required":["mode","kind","encryptedContent","iv","sealedDek"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"server-readable"},"kind":{"type":"string","enum":["journal","canvas"]},"plainBody":{"type":"string","minLength":1,"maxLength":750000}},"required":["mode","kind","plainBody"],"additionalProperties":false}]}},"required":["captureId","ownerSubject","content"],"additionalProperties":false}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/write/create_sealed_capture":{"post":{"tags":["kvark"],"summary":"Create a Kvark sealed deposit","description":"Create one untitled sealed deposit from caller-sealed ciphertext and sealedDek. Seal locally with `furnace kvark sealed-deposit`; plaintext never crosses the wire. The deposit reveals only its existence, createdAt, and sealed flag, and no API surface can read its body until the vault owner unlocks.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_kvark_write_create_sealed_capture","responses":{"200":{"description":"Create a Kvark sealed deposit","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"identity":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["note","task","drawing"]},"visibility":{"type":"string","enum":["zero-knowledge","server-readable"]},"dekEnvelope":{"type":"object","properties":{"version":{"type":"number","const":1},"wrappedDek":{"type":"string","minLength":1,"maxLength":4096},"wrapIv":{"type":"string","minLength":1,"maxLength":256}},"required":["version","wrappedDek","wrapIv"],"additionalProperties":false},"title":{"type":"string","maxLength":500},"sealed":{"type":"boolean","const":true},"everServerReadable":{"type":"boolean"},"vaultId":{"type":"string"},"collectionId":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","propertyNames":{"type":"string","maxLength":64},"additionalProperties":{"type":"string","maxLength":4096}},"sectionId":{"type":"string"},"archived":{"type":"boolean"},"createdAt":{"type":"number"},"updatedAt":{"type":"number"},"boostedUntil":{"type":"number"},"combinePending":{"type":"object","properties":{"sourceIds":{"minItems":2,"maxItems":100,"type":"array","items":{"type":"string","minLength":1,"maxLength":128}},"startedAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"expiresAt":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["sourceIds","startedAt","expiresAt"],"additionalProperties":false},"boardId":{"type":"string","minLength":1,"maxLength":128},"trashedAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"purgeAfter":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","tags","archived","createdAt","updatedAt"],"additionalProperties":false},"block":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128},"nukleonId":{"type":"string","minLength":1,"maxLength":128},"order":{"type":"number"},"createdAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"updatedAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"kind":{"type":"string","const":"journal"}},"required":["id","nukleonId","order","createdAt","updatedAt","kind"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128},"nukleonId":{"type":"string","minLength":1,"maxLength":128},"order":{"type":"number"},"createdAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"updatedAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"kind":{"type":"string","const":"canvas"},"placement":{"type":"string","const":"inline"}},"required":["id","nukleonId","order","createdAt","updatedAt","kind"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128},"nukleonId":{"type":"string","minLength":1,"maxLength":128},"order":{"type":"number"},"createdAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"updatedAt":{"type":"integer","minimum":0,"maximum":9007199254740991},"kind":{"type":"string","const":"list"},"childNukleonId":{"type":"string","minLength":1,"maxLength":128},"boardId":{"type":"string","minLength":1,"maxLength":128},"renderStyle":{"default":"checklist","type":"string","enum":["checklist","board"]}},"required":["id","nukleonId","order","createdAt","updatedAt","kind","childNukleonId","renderStyle"],"additionalProperties":false}]},"content":{"type":"object","properties":{"encryptedContent":{"type":"string"},"iv":{"type":"string"},"sealedDek":{"type":"object","properties":{"ephX25519":{"type":"string","minLength":1,"maxLength":256},"mlkemCt":{"type":"string","minLength":1,"maxLength":4096},"iv":{"type":"string","minLength":1,"maxLength":256},"wrapped":{"type":"string","minLength":1,"maxLength":512}},"required":["ephX25519","mlkemCt","iv","wrapped"],"additionalProperties":false},"plainBody":{"type":"string"},"updatedAt":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["encryptedContent","iv","updatedAt"],"additionalProperties":false}},"required":["identity","block","content"],"additionalProperties":false}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"encryptedContent":{"type":"string","minLength":1,"maxLength":750000},"iv":{"type":"string","minLength":1,"maxLength":256},"sealedDek":{"type":"object","properties":{"ephX25519":{"type":"string","minLength":1,"maxLength":256},"mlkemCt":{"type":"string","minLength":1,"maxLength":4096},"iv":{"type":"string","minLength":1,"maxLength":256},"wrapped":{"type":"string","minLength":1,"maxLength":512}},"required":["ephX25519","mlkemCt","iv","wrapped"],"additionalProperties":false}},"required":["encryptedContent","iv","sealedDek"],"additionalProperties":false}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/kvark/read/get_capture_public_bundle":{"post":{"tags":["kvark"],"summary":"Get the Kvark sealed-deposit public bundle","description":"Return the caller's sealed-deposit public bundle, or null until the vault owner unlocks Kvark once. Bodies cross the wire only as ciphertext; seal locally with `furnace kvark sealed-deposit`. A deposit reveals only its existence, createdAt, and sealed flag, and no API surface can read its body until the vault owner unlocks.","operationId":"post_kvark_read_get_capture_public_bundle","responses":{"200":{"description":"Get the Kvark sealed-deposit public bundle","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"type":"object","properties":{"x25519":{"type":"string","minLength":1,"maxLength":256},"mlkem":{"type":"string","minLength":1,"maxLength":4096}},"required":["x25519","mlkem"],"additionalProperties":false},{"type":"null"}]}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content":{"get":{"tags":["content"],"summary":"List content in a namespace","description":"Reader-filtered list of content. Editors see drafts; readers see only published items they can access.","operationId":"get_content","responses":{"200":{"description":"Page of content summaries","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContentSummary"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/tree":{"get":{"tags":["content"],"summary":"Get the namespace nav tree","description":"Returns the full reader-filtered nav tree (nodes with paths). Use this to build site navigation.","operationId":"get_content_by_namespace_tree","responses":{"200":{"description":"Namespace tree","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/NamespaceTree"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/by-path":{"get":{"tags":["content"],"summary":"Resolve content by URL path","description":"Resolve content by URL path","operationId":"get_content_by_namespace_by_path","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"path","in":"query","required":true,"description":"URL path within the namespace","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}":{"get":{"tags":["content"],"summary":"Get content by id","description":"Get content by id","operationId":"get_content_by_namespace_by_id","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["content"],"summary":"Update a content page","description":"Patch fields on a page. Editing `body` rotates the previous draft into version history. `customData` replaces the whole object — see the field description before sending it.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"body":{"type":"string","description":"Markdown — replaces current draft, prior draft rotates into history"},"tags":{"type":"array","items":{"type":"string"}},"featuredImage":{"type":["string","null"],"description":"Asset id or null to clear"},"customData":{"type":"object","additionalProperties":{"type":"string"},"description":"REPLACES the whole object — every key you want to keep must be included, or it is deleted. For layout changes use PATCH `/template` or `/custom-layout`, which merge a single key. `layoutDocument` is validated on write and rejected if invalid."}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["content"],"summary":"Delete a content page","description":"Pass `?deleteChildren=true` to cascade-delete descendants — otherwise the call fails if any exist.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_content_by_namespace_by_id","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"},"deletedIds":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"deleteChildren","in":"query","schema":{"type":"boolean"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/versions":{"get":{"tags":["content"],"summary":"List version history (or read a specific version)","description":"Without `index`, returns the full version history. With `index`, returns one version body. By convention `-1` = current draft, `-2` = current published, `0..N` = stored versions newest-first.","operationId":"get_content_by_namespace_by_id_versions","responses":{"200":{"description":"History or single version","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContentVersion"}}}},{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentVersion"}}}]}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"index","in":"query","description":"Optional: read a single version by index","schema":{"type":"integer"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}":{"post":{"tags":["content"],"summary":"Create a content page","description":"`parentId` of `null` (or omitted) creates a root-level page; `urlSegment` is auto-generated from title if omitted. `customData` seeds the page-metadata bag at creation, so a new page never needs a follow-up PATCH to set its `template`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace","responses":{"201":{"description":"Content created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"parentId":{"type":["string","null"]},"urlSegment":{"type":"string"},"body":{"type":"string","description":"Markdown"},"isCategory":{"type":"boolean"},"customData":{"type":"object","additionalProperties":{"type":"string"},"description":"Free-form string metadata. `template` names a page layout; `layoutDocument` is validated on write and rejected if invalid."}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/publish":{"post":{"tags":["content"],"summary":"Publish the current draft","description":"Publish the current draft\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_publish","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"customPublishedAt":{"type":"integer","description":"Optional epoch ms backdate"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/unpublish":{"post":{"tags":["content"],"summary":"Revert a page to draft-only state","description":"Revert a page to draft-only state\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_unpublish","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/schedule":{"post":{"tags":["content"],"summary":"Schedule a page for future publication","description":"Schedule a page for future publication\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_schedule","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scheduledAt"],"properties":{"scheduledAt":{"type":"integer","description":"Epoch ms in the future"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/duplicate":{"post":{"tags":["content"],"summary":"Duplicate a page as a new draft sibling","description":"Duplicate a page as a new draft sibling\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_duplicate","responses":{"201":{"description":"Content created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/checkpoint":{"post":{"tags":["content"],"summary":"Save a version checkpoint","description":"Snapshot the current draft as a new version (newest at index 0). Use before risky edits.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_checkpoint","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/restore":{"post":{"tags":["content"],"summary":"Restore an earlier version into the draft","description":"Restore an earlier version into the draft\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_restore","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["versionIndex"],"properties":{"versionIndex":{"type":"integer","minimum":0}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/template":{"patch":{"tags":["content"],"summary":"Set the page layout","description":"Points the page at a layout by id — a code layout the app ships, or a named layout from `/api/v1/content-layouts/{namespace}`. `null` returns the page to single-column. Merges the one key, so unlike PATCH `customData` it cannot drop sibling metadata. Unknown ids are accepted and degrade at render time.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_template","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template"],"properties":{"template":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/custom-layout":{"patch":{"tags":["content"],"summary":"Set the page's one-off layout document","description":"Stores a layout document belonging to this page alone, as a JSON string, and sets `template` to `custom`. `null` clears both. Validated against the SDL layout profile on write and rejected if invalid. Merges the one key, so it cannot drop sibling metadata.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_custom_layout","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"document":{"type":["string","null"],"description":"JSON-stringified SDL layout document, or null to clear"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/promote-layout":{"post":{"tags":["content"],"summary":"Promote the page's one-off layout to a named layout","description":"Creates a named layout from the page's one-off document and repoints the page at it, atomically. Requires both `update:content` and `manage:content_layouts`. Fails if the page has no one-off document or the slug is taken.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_id_promote_layout","responses":{"200":{"description":"Page repointed at the new named layout","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","slug"],"properties":{"id":{"type":"string"},"slug":{"type":"string"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","label"],"properties":{"slug":{"type":"string"},"label":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/move":{"patch":{"tags":["content"],"summary":"Re-parent a page","description":"Re-parent a page\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_move","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newParentId"],"properties":{"newParentId":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/url-segment":{"patch":{"tags":["content"],"summary":"Rename the URL segment","description":"Rename the URL segment\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_url_segment","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newSegment"],"properties":{"newSegment":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/reorder":{"patch":{"tags":["content"],"summary":"Reorder a page among its siblings","description":"Pin after `afterId` or before `beforeId`. Pass `null` for first/last.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_reorder","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"afterId":{"type":["string","null"]},"beforeId":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/flags":{"patch":{"tags":["content"],"summary":"Set visibility flags on a page","description":"`hidden` removes the page from reader navigation while keeping it URL-addressable (per-node — descendants are not affected). `startsAt` opens the schedule window; `endsAt` closes it. Pass `null` for either to clear; omit a field to leave it unchanged.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_flags","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hidden":{"type":"boolean"},"startsAt":{"type":["integer","null"]},"endsAt":{"type":["integer","null"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/access":{"patch":{"tags":["content"],"summary":"Set page access level","description":"Set page access level\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_by_namespace_by_id_access","responses":{"200":{"description":"Content document","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentDocument"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["access"],"properties":{"access":{"$ref":"#/components/schemas/ContentAccess"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/stats":{"get":{"tags":["content"],"summary":"Reaction + view stats for a content item","description":"Requires `read:analytics` in the namespace. `path` is the resolved nav-tree path.","operationId":"get_content_by_namespace_by_id_stats","responses":{"200":{"description":"Stats (null if unauthorized)"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"path","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/reactions":{"get":{"tags":["content"],"summary":"Emoji reaction counts for a content item","description":"Emoji reaction counts for a content item","operationId":"get_content_by_namespace_by_id_reactions","responses":{"200":{"description":"Reaction map (empty if no access)"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{id}/comments":{"get":{"tags":["content"],"summary":"List comments on a content item","description":"Content-access gated. Flagged/rejected hidden unless caller holds moderate/edit:comments.","operationId":"get_content_by_namespace_by_id_comments","responses":{"200":{"description":"Comments, replies, reactions, pagination"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/comments-moderation":{"get":{"tags":["content"],"summary":"List comments for moderation","description":"Requires moderate:comments or edit:comments. Optional `status` filter.","operationId":"get_content_by_namespace_comments_moderation","responses":{"200":{"description":"Moderation queue, newest first"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","approved","flagged","rejected"]}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{commentId}/moderate-comment":{"post":{"tags":["content"],"summary":"Set a comment moderation status","description":"Requires moderate:comments or edit:comments. `{commentId}` is the comment id.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_commentId_moderate_comment","responses":{"200":{"description":"Moderation status applied"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["approved","flagged","rejected"]},"reason":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/{commentId}/moderator-edit":{"post":{"tags":["content"],"summary":"Moderator-edit a comment body","description":"Requires moderate:comments or edit:comments. Locks and approves the comment.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_by_namespace_by_commentId_moderator_edit","responses":{"200":{"description":"Edited"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/nav-tree-paths":{"get":{"tags":["content"],"summary":"Nested nav tree with resolved paths","description":"Nested nav tree with resolved paths","operationId":"get_content_by_namespace_nav_tree_paths","responses":{"200":{"description":"Nested tree with path/depth/children"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/audit-schedule":{"get":{"tags":["content"],"summary":"Audit nav-tree schedule migration state (cross-namespace)","description":"Service token or super-admin (read:analytics in access-control) only. `{namespace}` is ignored.","operationId":"get_content_by_namespace_audit_schedule","responses":{"200":{"description":"Per-namespace legacy-shape counts"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/kv-list":{"get":{"tags":["content"],"summary":"List raw content KV entries","description":"Access-filtered KV listing. Editors see drafts; readers see published, permitted entries. Platform-owned families under the `__` sigil (`__layout:*`, `__content:card:*`, `__access:*`) are never listed — read those through their own endpoints.","operationId":"get_content_by_namespace_kv_list","responses":{"200":{"description":"Page of KV entries"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}},{"name":"prefix","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content/{namespace}/tags":{"get":{"tags":["content"],"summary":"List all unique tags in a namespace","description":"List all unique tags in a namespace","operationId":"get_content_by_namespace_tags","responses":{"200":{"description":"Sorted unique tags"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `docs`).","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/content-layouts/{namespace}":{"get":{"tags":["content_layouts"],"summary":"List named content layouts","description":"Slug-ordered layouts with their full SDL documents. Needs `manage:content_layouts` or `update:content`.","operationId":"get_content_layouts_by_namespace","responses":{"200":{"description":"Named content layouts","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContentLayout"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `falcata-website`).","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["content_layouts"],"summary":"Create a named content layout","description":"Fails if the slug is already in use in this namespace.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_content_layouts_by_namespace","responses":{"201":{"description":"Layout created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentLayout"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `falcata-website`).","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentLayoutInput"}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content-layouts/{namespace}/{slug}":{"get":{"tags":["content_layouts"],"summary":"Read one named content layout","description":"Read one named content layout","operationId":"get_content_layouts_by_namespace_by_slug","responses":{"200":{"description":"Named content layout","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentLayout"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `falcata-website`).","schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["content_layouts"],"summary":"Update a named content layout","description":"Omitted fields keep their stored value; `description: null` clears it. The slug is immutable.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_content_layouts_by_namespace_by_slug","responses":{"200":{"description":"Named content layout","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContentLayout"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `falcata-website`).","schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":["string","null"]},"document":{"type":"object","description":"SDL layout document in the layout profile: a Stack/Row/Grid/Split/… tree whose leaves include `ContentSlot` nodes, one per editable region. Statics only — no data, vars, bindings, or conditionals. Validated on write; an invalid document is rejected, never stored."}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["content_layouts"],"summary":"Delete a named content layout","description":"Pages still naming it keep their content and fall back to the default single-column layout.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_content_layouts_by_namespace_by_slug","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"slug":{"type":"string"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `falcata-website`).","schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/content-layouts/{namespace}/{slug}/usage":{"get":{"tags":["content_layouts"],"summary":"Count pages using a named content layout","description":"The scan is bounded at 1000 pages; `count: 1001` means the namespace is larger than the bound and the exact number is unknown.","operationId":"get_content_layouts_by_namespace_by_slug_usage","responses":{"200":{"description":"Usage count","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["slug","count"],"properties":{"slug":{"type":"string"},"count":{"type":"integer"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"description":"Content namespace (e.g. `marozzo`, `falcata-website`).","schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/communications/config/enabled-namespaces":{"get":{"tags":["communications"],"summary":"Get enabled namespaces","description":"Get enabled namespaces","operationId":"get_communications_config_enabled_namespaces","responses":{"200":{"description":"Enabled namespace slugs"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["communications"],"summary":"Set enabled namespaces","description":"Set enabled namespaces\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_communications_config_enabled_namespaces","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["namespaces"],"properties":{"namespaces":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/subscribers":{"get":{"tags":["communications"],"summary":"List email subscribers","description":"List email subscribers","operationId":"get_communications_by_namespace_subscribers","responses":{"200":{"description":"Paginated subscribers"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["subscribed","unsubscribed","bounced","complained"]}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["communications"],"summary":"Add a subscriber","description":"Add a subscriber\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_by_namespace_subscribers","responses":{"200":{"description":"Subscriber id"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","source"],"properties":{"email":{"type":"string"},"source":{"type":"string","enum":["manual","signup","migration"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["communications"],"summary":"Remove a subscriber","description":"Remove a subscriber\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_communications_by_namespace_subscribers","responses":{"200":{"description":"Removed"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"email","in":"query","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/subscribers/tags":{"get":{"tags":["communications"],"summary":"List subscriber tags","description":"List subscriber tags","operationId":"get_communications_by_namespace_subscribers_tags","responses":{"200":{"description":"Unique tags"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/subscribers/counts":{"get":{"tags":["communications"],"summary":"Subscriber status counts","description":"Subscriber status counts","operationId":"get_communications_by_namespace_subscribers_counts","responses":{"200":{"description":"Counts by status"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/communications/subscribers/{subscriberId}/tags":{"patch":{"tags":["communications"],"summary":"Update subscriber tags","description":"Update subscriber tags\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_communications_subscribers_by_subscriberId_tags","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/campaigns":{"get":{"tags":["communications"],"summary":"List email campaigns","description":"List email campaigns","operationId":"get_communications_by_namespace_campaigns","responses":{"200":{"description":"Paginated campaigns"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","sending","sent","failed","partially_sent"]}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["communications"],"summary":"Create a draft campaign","description":"Create a draft campaign\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_by_namespace_campaigns","responses":{"200":{"description":"Campaign id"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"type":"string"},"previewText":{"type":"string"},"mdBody":{"type":"string"},"audienceTags":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/campaigns/{campaignId}":{"get":{"tags":["communications"],"summary":"Get a campaign","description":"Get a campaign","operationId":"get_communications_campaigns_by_campaignId","responses":{"200":{"description":"Campaign"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["communications"],"summary":"Update a draft campaign","description":"Update a draft campaign\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_communications_campaigns_by_campaignId","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string"},"previewText":{"type":"string"},"mdBody":{"type":"string"},"audienceTags":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["communications"],"summary":"Delete a campaign","description":"Delete a campaign\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_communications_campaigns_by_campaignId","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/campaigns/{campaignId}/stats":{"get":{"tags":["communications"],"summary":"Campaign delivery stats","description":"Campaign delivery stats","operationId":"get_communications_campaigns_by_campaignId_stats","responses":{"200":{"description":"Delivery stats"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/audience-size":{"get":{"tags":["communications"],"summary":"Estimate audience size","description":"Estimate audience size","operationId":"get_communications_by_namespace_audience_size","responses":{"200":{"description":"Recipient count"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"tags","in":"query","schema":{"type":"string","description":"Comma-separated audience tags"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/communications/campaigns/{campaignId}/reset-draft":{"post":{"tags":["communications"],"summary":"Reset campaign to draft","description":"Reset campaign to draft\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_campaigns_by_campaignId_reset_draft","responses":{"200":{"description":"Reset"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/campaigns/{campaignId}/duplicate":{"post":{"tags":["communications"],"summary":"Duplicate a campaign","description":"Duplicate a campaign\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_campaigns_by_campaignId_duplicate","responses":{"200":{"description":"New campaign id"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/campaigns/{campaignId}/send":{"post":{"tags":["communications"],"summary":"Send a campaign","description":"Send a campaign\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_campaigns_by_campaignId_send","responses":{"200":{"description":"Send started"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/campaigns/{campaignId}/test-email":{"post":{"tags":["communications"],"summary":"Send a test email","description":"Send a test email\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_campaigns_by_campaignId_test_email","responses":{"200":{"description":"Test sent"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"campaignId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recipientEmail"],"properties":{"recipientEmail":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/templates":{"get":{"tags":["communications"],"summary":"List email templates","description":"List email templates","operationId":"get_communications_by_namespace_templates","responses":{"200":{"description":"Templates"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["communications"],"summary":"Create an email template","description":"Create an email template\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_communications_by_namespace_templates","responses":{"200":{"description":"Template id"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","mdBody"],"properties":{"name":{"type":"string"},"mdBody":{"type":"string"},"audienceTags":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/templates/{templateId}":{"delete":{"tags":["communications"],"summary":"Delete an email template","description":"Delete an email template\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_communications_templates_by_templateId","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/config/legal":{"get":{"tags":["communications"],"summary":"Get legal footer config","description":"Get legal footer config","operationId":"get_communications_by_namespace_config_legal","responses":{"200":{"description":"Legal config"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["communications"],"summary":"Set legal footer config","description":"Set legal footer config\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_communications_by_namespace_config_legal","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"companyName":{"type":"string"},"addressLine1":{"type":"string"},"addressLine2":{"type":"string"},"city":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"unsubscribeNote":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/communications/{namespace}/config/email":{"get":{"tags":["communications"],"summary":"Get email sender config","description":"Get email sender config","operationId":"get_communications_by_namespace_config_email","responses":{"200":{"description":"Email config"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["communications"],"summary":"Set email sender config","description":"Set email sender config\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_communications_by_namespace_config_email","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fromAddress","fromName"],"properties":{"fromAddress":{"type":"string"},"fromName":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/ledger/read/{operation}":{"post":{"tags":["ledger"],"summary":"Run a Ledger read operation","description":"Supported operations: get_config, list_journal_entries, get_journal_entry, list_entry_audit, list_audit, search_journal_entries, list_counterparties, list_clearing_entries, clearing_count, list_scans, get_scan, list_customers, get_customer, list_work_types, list_customer_rates, list_all_customer_rates, list_time_entries, get_time_entry, list_unbilled_for_customer, summarize_uninvoiced, list_invoices, get_invoice, compute_vat_report, compute_oss_report, export_oss_csv, compute_tilinpaatos, get_tilinpaatos_config, list_saved_reports, get_saved_report, dashboard_summary","operationId":"post_ledger_read_by_operation","responses":{"200":{"description":"Ledger operation result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"operation","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/ledger/write/{operation}":{"post":{"tags":["ledger"],"summary":"Run a Ledger write operation","description":"Supported operations: save_opening_balances, create_journal_entry, update_journal_entry, set_scan_extraction, attach_scans_to_entry, create_customer, update_customer, archive_customer, delete_customer, create_work_type, update_work_type, archive_work_type, delete_work_type, set_customer_rate, delete_customer_rate, create_time_entry, update_time_entry, delete_time_entry, create_invoice_draft, update_invoice_draft, delete_invoice_draft, issue_invoice, mark_invoice_paid, credit_invoice, save_tilinpaatos_config, save_report\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_ledger_write_by_operation","responses":{"200":{"description":"Ledger operation result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"operation","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/ledger/action/read/{operation}":{"post":{"tags":["ledger"],"summary":"Run a Ledger read action","description":"Supported operations: get_attachment_url, find_dangling_attachments, extract_from_attachments, list_stripe_activity, list_revolut_activity, get_saved_report_pdf_url","operationId":"post_ledger_action_read_by_operation","responses":{"200":{"description":"Ledger action result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"operation","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/ledger/action/write/{operation}":{"post":{"tags":["ledger"],"summary":"Run a Ledger write action","description":"Supported operations: delete_journal_entry, delete_scan, delete_report, generate_invoice_pdf, verify_eu_vat_rates, upload_attachment, upload_scan, delete_attachment, sync_stripe_balance_transactions, sync_revolut_transactions, prepare_revolut_connect, generate_report_pdf\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_ledger_action_write_by_operation","responses":{"200":{"description":"Ledger action result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"operation","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/overview":{"get":{"tags":["analytics"],"summary":"Period summary with prior-window trend","description":"Pass `days` for a trailing window, or `since`/`until` for a pinned range. Requires `read:analytics` in the namespace.","operationId":"get_analytics_by_namespace_overview","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/AnalyticsOverview"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/timeseries":{"get":{"tags":["analytics"],"summary":"Bucketed event counts","description":"Group events by `period` (`hour` or `day`), optionally filtered by `eventName`.","operationId":"get_analytics_by_namespace_timeseries","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeSeriesPoint"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}},{"name":"period","in":"query","required":true,"schema":{"type":"string","enum":["hour","day"]}},{"name":"eventName","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/top-paths":{"get":{"tags":["analytics"],"summary":"Top paths by event volume","description":"Optional `eventName` narrows to a single event type — pass `page_view` for true page reads.","operationId":"get_analytics_by_namespace_top_paths","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TopPath"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100},"description":"Default 25, capped at 100"},{"name":"eventName","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/top-referrers":{"get":{"tags":["analytics"],"summary":"Top cross-origin referrers by session volume","description":"Direct visits and same-origin navigation are excluded. Captured on `page_view` events only.","operationId":"get_analytics_by_namespace_top_referrers","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TopReferrer"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100},"description":"Default 25, capped at 100"}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/event-names":{"get":{"tags":["analytics"],"summary":"Distinct event names in the window","description":"Distinct event names in the window","operationId":"get_analytics_by_namespace_event_names","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EventNameStat"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/list-events":{"get":{"tags":["analytics"],"summary":"List raw analytics events","description":"Newest-first raw event rows, optionally filtered by `eventName` and time window. Max `limit` 1000.","operationId":"get_analytics_by_namespace_list_events","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsEvent"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}},{"name":"eventName","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/top-searches":{"get":{"tags":["analytics"],"summary":"Top palette search queries","description":"Ranks `palette_search` queries with sessions, average result count, and zero-result rate.","operationId":"get_analytics_by_namespace_top_searches","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TopSearch"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100},"description":"Default 25, capped at 100"}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/feedback-stats":{"get":{"tags":["analytics"],"summary":"Feedback submission stats","description":"Aggregates `feedback_submitted` events with prior-window trend and a daily time series.","operationId":"get_analytics_by_namespace_feedback_stats","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/FeedbackStats"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"},{"name":"since","in":"query","description":"Window start — ms timestamp or ISO 8601 string","schema":{"type":["integer","string"]}},{"name":"until","in":"query","description":"Window end — defaults to now","schema":{"type":["integer","string"]}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/{namespace}/user-activity":{"get":{"tags":["analytics"],"summary":"Caller's own activity stats","description":"Per-user activity for the calling PAT's user. Service tokens receive null (no user identity). `data` is null when unavailable.","operationId":"get_analytics_by_namespace_user_activity","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/UserActivityStats"},{"type":"null"}]}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1},"description":"Trailing N-day window from now"}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/analytics/namespaces":{"get":{"tags":["analytics"],"summary":"List namespaces the caller can read analytics for","description":"Sorted app namespaces where the caller holds `read:analytics`. Service tokens see every namespace.","operationId":"get_analytics_namespaces","responses":{"200":{"description":"Analytics result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/studio/query":{"post":{"tags":["studio"],"summary":"Run a governed analytics query spec","description":"Submit a Studio query spec and get the computed rows plus an optional multi-series pivot. The flexible counterpart to the fixed analytics endpoints. Requires `read:analytics` in the spec namespace.","operationId":"post_studio_query","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudioQueryResult"}}}}},"description":"Computed query result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioQuerySpec"}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/studio/dashboards":{"get":{"tags":["studio"],"summary":"List the caller's saved dashboards","description":"Most-recently-updated first. Owner-scoped — requires a user-bound PAT (service tokens have no dashboards).","operationId":"get_studio_dashboards","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudioDashboard"}}}}}},"description":"The caller’s dashboards"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["studio"],"summary":"Create or update a saved dashboard","description":"Omit `id` to create; include it to update. Owner-scoped (PAT). At most 50 dashboards per user, 24 charts each.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_studio_dashboards","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudioDashboard"}}}}},"description":"Updated dashboard"},"201":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudioDashboard"}}}}},"description":"Created dashboard"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Omit to create a new dashboard; include to update an existing one."},"name":{"type":"string"},"description":{"type":"string"},"charts":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["stat","area","line","bar","column","table","multiLine","groupedBar","stackedBar","stackedArea"]},"title":{"type":"string"},"spec":{"type":"object","properties":{"source":{"type":"string","enum":["analytics"],"description":"Always \"analytics\"."},"namespace":{"type":"string","description":"Which app/tenant to query. Must be one of the namespaces listed as available to you in the system prompt."},"eventName":{"type":"string","description":"Optional: restrict to a single event name (e.g. \"page_view\", \"ai_chat\"). Omit to include all events."},"filters":{"type":"array","description":"Optional: up to 10 equality filters, all of which must match (AND).","items":{"type":"object","properties":{"field":{"type":"string","description":"One of: path, referrer, name, or properties.<key> (e.g. \"properties.tier\")."},"op":{"type":"string","enum":["eq","neq","in"],"description":"\"eq\"/\"neq\" compare to a single string value; \"in\" matches any value in an array."},"value":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"A string for \"eq\"/\"neq\"; an array of strings for \"in\"."}},"required":["field","op","value"],"additionalProperties":false}},"groupBy":{"type":"object","description":"Optional: break the measure down by one dimension. Omit for a single total (big number).","properties":{"dimension":{"type":"string","description":"One of: path, referrer, name, time, or properties.<key>. Use \"time\" for a trend across the window."},"timeBucket":{"type":"string","enum":["hour","day","week"],"description":"Only with dimension \"time\": the bucket width. Defaults to \"day\"."}},"required":["dimension"],"additionalProperties":false},"series":{"type":"object","description":"Optional: split the measure into multiple series by a SECOND categorical dimension — e.g. groupBy \"time\" + series by \"name\" draws one line per event type; groupBy a category + series draws grouped bars. Requires groupBy and must differ from it. Use only when comparing a handful of categories across the primary axis.","properties":{"dimension":{"type":"string","description":"One of: path, referrer, name, or properties.<key>. NOT \"time\" — time is the primary axis."},"limit":{"type":"number","description":"Optional: keep only the top-N series by measure (default 6, max 8)."}},"required":["dimension"],"additionalProperties":false},"measure":{"type":"object","description":"What to compute over the matched events.","properties":{"fn":{"type":"string","enum":["count","sessions","users","anonymous","sum","avg","p50","p95"],"description":"count = number of events; sessions/users/anonymous = distinct counts; sum/avg/p50/p95 = numeric statistics over a property field."},"field":{"type":"string","description":"Required for sum/avg/p50/p95: a properties.<key> holding a number (e.g. \"properties.estimatedCostUsd\"). Omit for count/sessions/users/anonymous."}},"required":["fn"],"additionalProperties":false},"range":{"description":"The time window. Either a trailing number of days, or absolute since/until in epoch milliseconds. Capped server-side at 90 days.","anyOf":[{"type":"object","properties":{"days":{"type":"number","description":"Trailing window length in days (1–90)."}},"required":["days"],"additionalProperties":false},{"type":"object","properties":{"since":{"type":"number","description":"Window start, epoch milliseconds."},"until":{"type":"number","description":"Window end, epoch milliseconds. Defaults to now."}},"required":["since"],"additionalProperties":false}]},"limit":{"type":"number","description":"Optional: max rows for a categorical breakdown (1–100, default 50). Ignored for a time series, which is always returned whole."},"kind":{"type":"string","enum":["aggregate","experiment"],"description":"The query type. Omit or \"aggregate\" for the normal measure/groupBy analytics above. \"experiment\" instead measures an A/B experiment: it correlates flag exposures with a later outcome event to report per-variant conversion — set flagKey + outcomeEvent (and optionally exposureEvent) plus a range; measure/groupBy/series/filters/limit do not apply."},"flagKey":{"type":"string","description":"Experiment kind only: the experiment flag key whose variants to measure (matched against exposure events' properties.flag)."},"outcomeEvent":{"type":"string","description":"Experiment kind only: the event name that counts as a conversion (e.g. \"checkout_complete\", \"signup\"). A variant converts when an exposed identity emits this event at or after its first exposure."},"exposureEvent":{"type":"string","description":"Experiment kind only, optional: the exposure event name. Defaults to \"experiment_exposure\" (what the flag client emits on first variant read)."}},"required":["source","namespace","measure","range"],"additionalProperties":false},"window":{"type":"object","description":"Generation-time snapshot of the resolved window. Stored, but not authoritative: `spec.range` decides the span a chart shows, so a relative `{days}` range slides forward on every load while this stays pinned. Send the window the spec resolves to now.","properties":{"since":{"type":"integer"},"until":{"type":"integer"}},"required":["since","until"]},"targetSlug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Optional kebab-case app slug this widget targets (cross-app dashboards)."}},"required":["kind","title","spec","window"],"additionalProperties":false},"minItems":1}},"required":["name","charts"],"additionalProperties":false}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/studio/dashboards/{id}":{"get":{"tags":["studio"],"summary":"Get a saved dashboard by id","description":"Get a saved dashboard by id","operationId":"get_studio_dashboards_by_id","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudioDashboard"}}}}},"description":"The dashboard"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Dashboard id","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"delete":{"tags":["studio"],"summary":"Delete a saved dashboard by id","description":"Delete a saved dashboard by id\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_studio_dashboards_by_id","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"boolean"}}}}}}},"description":"Whether a dashboard was removed"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Dashboard id","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/marozzo/chat":{"post":{"tags":["marozzo"],"summary":"Send a turn to the Marozzo assistant","description":"Non-streaming. The server runs the full agentic loop and returns the complete reply. Pass `threadId` to continue a thread; omit to start a new one (the new id is in the response). Pass `retry=true` (with a `threadId` whose last turn is unanswered) to re-run a turn that previously failed mid-stream. Requires an active membership; service tokens cannot use this.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_marozzo_chat","responses":{"200":{"description":"Assistant turn","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MarozzoChatResult"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"User message. Required unless retry=true."},"threadId":{"type":"string"},"retry":{"type":"boolean"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/marozzo/threads/{id}":{"get":{"tags":["marozzo"],"summary":"Get full thread history","description":"Owner-only. Returns \"Thread not found\" both when the thread does not exist and when the calling user does not own it — owner existence is intentionally not leaked.","operationId":"get_marozzo_threads_by_id","responses":{"200":{"description":"Thread history","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MarozzoThreadHistory"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/dictionaries/search":{"get":{"tags":["dictionaries"],"summary":"Search Florio (1611) and Crusca (1612) dictionaries","description":"Dual-lane search (vector + keyword) across the two historical Italian dictionaries used by the Marozzo assistant for RAG. Merges results by similarity score. Pass `source=florio|crusca` to restrict to one dictionary.","operationId":"get_dictionaries_search","responses":{"200":{"description":"Dictionary hits ordered by similarity score.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DictionaryHit"}},"meta":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Search query."},{"name":"limit","in":"query","schema":{"type":"integer"},"description":"Maximum results (default 20, max 100)."},{"name":"source","in":"query","schema":{"type":"string","enum":["florio","crusca","all"]},"description":"Dictionary to search (default `all`)."}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/dictionaries/treatises/search":{"get":{"tags":["dictionaries"],"summary":"Search the three Bolognese treatises (1531 / 1550 / 1572)","description":"Dual-lane search (vector + Italian/English keyword) across Manciolino, Marozzo Opera Nova, and dall'Agocchie. Merges by similarity score. Pass `source=manciolino|opera_nova|dall_agocchie` to restrict.","operationId":"get_dictionaries_treatises_search","responses":{"200":{"description":"Treatise hits ordered by similarity score.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TreatiseHit"}},"meta":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Search query."},{"name":"limit","in":"query","schema":{"type":"integer"},"description":"Maximum results (default 20, max 100)."},{"name":"source","in":"query","schema":{"type":"string","enum":["manciolino","opera_nova","dall_agocchie","all"]},"description":"Treatise to search (default `all`)."}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/dictionaries/treatises/{source}/book/{book}":{"get":{"tags":["dictionaries"],"summary":"List all chapters of a treatise book","description":"Every chapter entry in one Libro. `source` is manciolino, opera_nova, or dall_agocchie.","operationId":"get_dictionaries_treatises_by_source_book_by_book","responses":{"200":{"description":"Chapter entries for the book.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"source","in":"path","required":true,"schema":{"type":"string","enum":["manciolino","opera_nova","dall_agocchie"]}},{"name":"book","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/dictionaries/treatises/{source}/chapter/{book}/{chapter}":{"get":{"tags":["dictionaries"],"summary":"Read one treatise chapter","description":"Single chapter entry by book + chapter. Returns 404 if absent.","operationId":"get_dictionaries_treatises_by_source_chapter_by_book_by_chapter","responses":{"200":{"description":"The chapter entry.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"source","in":"path","required":true,"schema":{"type":"string","enum":["manciolino","opera_nova","dall_agocchie"]}},{"name":"book","in":"path","required":true,"schema":{"type":"integer","minimum":1}},{"name":"chapter","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/{namespace}/hero-promos":{"get":{"tags":["hero_promos"],"summary":"List hero promos","description":"Returns hero promos in display order. Pass `?activeOnly=true` to filter to currently visible ones (enabled + within any configured schedule window).","operationId":"get_by_namespace_hero_promos","responses":{"200":{"description":"Hero promos","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HeroPromo"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"activeOnly","in":"query","schema":{"type":"boolean"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["hero_promos"],"summary":"Create a hero promo","description":"Creates a hero promo and appends it to the end of the display order.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_by_namespace_hero_promos","responses":{"201":{"description":"Hero promo created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/HeroPromo"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeroPromoInput"}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/{namespace}/hero-promos/{id}":{"patch":{"tags":["hero_promos"],"summary":"Replace a hero promo (all fields required)","description":"Replace a hero promo (all fields required)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_by_namespace_hero_promos_by_id","responses":{"200":{"description":"Hero promo","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/HeroPromo"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeroPromoInput"}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["hero_promos"],"summary":"Delete a hero promo","description":"Delete a hero promo\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_by_namespace_hero_promos_by_id","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/{namespace}/hero-promos/reorder":{"post":{"tags":["hero_promos"],"summary":"Set the hero promo display order","description":"Pass an array of ids in the desired order. Unknown ids are dropped; promos missing from the list are appended in their current order.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_by_namespace_hero_promos_reorder","responses":{"200":{"description":"New order","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"ordered":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderedIds"],"properties":{"orderedIds":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets":{"get":{"tags":["media"],"summary":"List media assets","description":"List media assets","operationId":"get_media_assets","responses":{"200":{"description":"Paginated assets","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["image","file"]}},{"name":"visibility","in":"query","schema":{"type":"string","enum":["public","protected"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","processing","ready","failed"]}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"tags","in":"query","description":"Comma-separated; asset must contain all","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}":{"get":{"tags":["media"],"summary":"Get a media asset","description":"Get a media asset","operationId":"get_media_assets_by_id","responses":{"200":{"description":"Asset","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MediaAsset"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["media"],"summary":"Update a media asset","description":"Update a media asset\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_media_assets_by_id","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"visibility":{"type":"string","enum":["public","protected"]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["media"],"summary":"Delete a media asset","description":"Delete a media asset\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_media_assets_by_id","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/batch-delete":{"post":{"tags":["media"],"summary":"Delete multiple media assets","description":"Delete multiple media assets\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_batch_delete","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/batch-tags":{"post":{"tags":["media"],"summary":"Add or remove tags across multiple assets","description":"Add or remove tags across multiple assets\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_batch_tags","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action","ids","tags"],"properties":{"action":{"type":"string","enum":["add","remove"]},"ids":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/url":{"post":{"tags":["media"],"summary":"Mint a signed URL for a protected asset","description":"Mint a signed URL for a protected asset\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_by_id_url","responses":{"200":{"description":"Signed URL"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"transformClass":{"type":"string","enum":["thumb","card","hero","full","square"]},"expiresInSeconds":{"type":"integer"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/namespaces":{"post":{"tags":["media"],"summary":"Set restricted asset availability (legacy)","description":"Legacy compatibility endpoint. Array means restricted availability; null or empty means library-only.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_by_id_namespaces","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["allowedNamespaces"],"properties":{"allowedNamespaces":{"type":["array","null"],"items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/usage-policy":{"post":{"tags":["media"],"summary":"Set where a media asset may be embedded","description":"Admin-only. Independent from public/protected visibility.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_by_id_usage_policy","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["usagePolicy"],"properties":{"usagePolicy":{"oneOf":[{"type":"object","required":["mode"],"properties":{"mode":{"type":"string","enum":["library-only","all"]}}},{"type":"object","required":["mode","namespaces"],"properties":{"mode":{"type":"string","enum":["restricted"]},"namespaces":{"type":"array","items":{"type":"string"}}}}]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/replace":{"post":{"tags":["media"],"summary":"Replace an existing image (base64 in JSON, max ~10 MB)","description":"Re-upload bytes for an existing image asset. The asset id is preserved; prior CDN objects are deleted and variants regenerate asynchronously. Image assets only.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_by_id_replace","responses":{"200":{"description":"Replacement queued"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mimeType","originalName","size","imageData"],"properties":{"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif"]},"originalName":{"type":"string"},"size":{"type":"integer"},"imageData":{"type":"string","description":"base64-encoded bytes (no data: prefix)"},"aiDescribe":{"type":"boolean","description":"Queue AI metadata suggestions from the replacement file (default false)."}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/regenerate-ai-metadata":{"post":{"tags":["media"],"summary":"Regenerate AI metadata suggestions for an image","description":"Re-fetch image bytes, run Sonnet tagging/description, and store the result in `aiSuggestion` without overwriting live metadata. Image assets only. Requires `media:admin`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_by_id_regenerate_ai_metadata","responses":{"200":{"description":"Generation result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"generated":{"type":"boolean"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/apply-ai-suggestion":{"post":{"tags":["media"],"summary":"Apply AI metadata suggestions to live fields","description":"Copy selected fields from `aiSuggestion` into the live asset. Each applied field is marked manually edited. Requires `media:admin`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_assets_by_id_apply_ai_suggestion","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"applyDisplayName":{"type":"boolean"},"applyDescription":{"type":"boolean"},"applyTags":{"type":"boolean"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/upload/image":{"post":{"tags":["media"],"summary":"Upload an image (base64 in JSON, max ~10 MB)","description":"Upload an image (base64 in JSON, max ~10 MB)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_upload_image","responses":{"201":{"description":"Created"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mimeType","originalName","size","visibility","imageData"],"properties":{"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif"]},"originalName":{"type":"string"},"size":{"type":"integer"},"visibility":{"type":"string","enum":["public","protected"]},"tags":{"type":"array","items":{"type":"string"}},"imageData":{"type":"string","description":"base64-encoded bytes (no data: prefix)"},"allowedNamespaces":{"type":"array","items":{"type":"string"},"description":"Protected-only namespace allowlist binding, set at upload time."},"usagePolicy":{"oneOf":[{"type":"object","required":["mode"],"properties":{"mode":{"type":"string","enum":["library-only","all"]}}},{"type":"object","required":["mode","namespaces"],"properties":{"mode":{"type":"string","enum":["restricted"]},"namespaces":{"type":"array","items":{"type":"string"}}}}]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/upload/file":{"post":{"tags":["media"],"summary":"Upload an arbitrary file (base64 in JSON)","description":"Upload an arbitrary file (base64 in JSON)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_upload_file","responses":{"201":{"description":"Created"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mimeType","originalName","size","visibility","fileData","extension"],"properties":{"mimeType":{"type":"string"},"originalName":{"type":"string"},"size":{"type":"integer"},"visibility":{"type":"string","enum":["public","protected"]},"tags":{"type":"array","items":{"type":"string"}},"fileData":{"type":"string"},"extension":{"type":"string"},"allowedNamespaces":{"type":"array","items":{"type":"string"},"description":"Protected-only namespace allowlist binding, set at upload time."},"usagePolicy":{"oneOf":[{"type":"object","required":["mode"],"properties":{"mode":{"type":"string","enum":["library-only","all"]}}},{"type":"object","required":["mode","namespaces"],"properties":{"mode":{"type":"string","enum":["restricted"]},"namespaces":{"type":"array","items":{"type":"string"}}}}]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/stats":{"get":{"tags":["media"],"summary":"Media library stats","description":"Media library stats","operationId":"get_media_stats","responses":{"200":{"description":"Stats"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/tags":{"get":{"tags":["media"],"summary":"Unique media tags","description":"Unique media tags","operationId":"get_media_tags","responses":{"200":{"description":"Tags"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/cdn-config":{"get":{"tags":["media"],"summary":"CDN base URLs","description":"CDN base URLs","operationId":"get_media_cdn_config","responses":{"200":{"description":"CDN config"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/videos":{"get":{"tags":["media"],"summary":"List videos","description":"List videos","operationId":"get_media_videos","responses":{"200":{"description":"Paginated videos"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{id}":{"get":{"tags":["media"],"summary":"Get a video","description":"Get a video","operationId":"get_media_videos_by_id","responses":{"200":{"description":"Video","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VideoAsset"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["media"],"summary":"Update a video","description":"Update a video\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_media_videos_by_id","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["media"],"summary":"Delete a video","description":"Delete a video\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_media_videos_by_id","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/by-bunny-id/{bunnyVideoId}":{"get":{"tags":["media"],"summary":"Resolve video metadata by Bunny id","description":"Resolve video metadata by Bunny id","operationId":"get_media_videos_by_bunny_id_by_bunnyVideoId","responses":{"200":{"description":"Video metadata"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"bunnyVideoId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/upload":{"post":{"tags":["media"],"summary":"Begin a video upload (TUS)","description":"Begin a video upload (TUS)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_upload","responses":{"201":{"description":"TUS session"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{id}/finalize":{"post":{"tags":["media"],"summary":"Finalize a video upload","description":"Finalize a video upload\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_by_id_finalize","responses":{"200":{"description":"Encoding state"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{id}/cancel":{"post":{"tags":["media"],"summary":"Cancel an in-flight video upload","description":"Cancel an in-flight video upload\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_by_id_cancel","responses":{"200":{"description":"Cancelled"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{id}/namespaces":{"post":{"tags":["media"],"summary":"Set restricted video availability (legacy)","description":"Legacy compatibility endpoint. Array means restricted availability; null or empty means library-only.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_by_id_namespaces","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["allowedNamespaces"],"properties":{"allowedNamespaces":{"type":["array","null"],"items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{id}/usage-policy":{"post":{"tags":["media"],"summary":"Set where a video may be embedded","description":"Admin-only. Independent from public/protected visibility.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_by_id_usage_policy","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["usagePolicy"],"properties":{"usagePolicy":{"oneOf":[{"type":"object","required":["mode"],"properties":{"mode":{"type":"string","enum":["library-only","all"]}}},{"type":"object","required":["mode","namespaces"],"properties":{"mode":{"type":"string","enum":["restricted"]},"namespaces":{"type":"array","items":{"type":"string"}}}}]}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{bunnyVideoId}/signed-url":{"post":{"tags":["media"],"summary":"Mint a signed embed URL for a protected video","description":"Mint a signed embed URL for a protected video","operationId":"post_media_videos_by_bunnyVideoId_signed_url","responses":{"200":{"description":"Signed URL"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"bunnyVideoId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/{bunnyVideoId}/thumbnails":{"post":{"tags":["media"],"summary":"Mint signed thumbnail URLs for a video","description":"Mint signed thumbnail URLs for a video\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_by_bunnyVideoId_thumbnails","responses":{"200":{"description":"Poster and preview URLs"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"bunnyVideoId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/batch-delete":{"post":{"tags":["media"],"summary":"Delete multiple videos","description":"Delete multiple videos\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_batch_delete","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/batch-tags":{"post":{"tags":["media"],"summary":"Add/remove tags on multiple videos","description":"Add/remove tags on multiple videos\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_media_videos_batch_tags","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/stats":{"get":{"tags":["media"],"summary":"Video library stats","description":"Video library stats","operationId":"get_media_videos_stats","responses":{"200":{"description":"Stats"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/videos/tags":{"get":{"tags":["media"],"summary":"Unique video tags","description":"Unique video tags","operationId":"get_media_videos_tags","responses":{"200":{"description":"Tags"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/{id}/resolve":{"get":{"tags":["media"],"summary":"Resolve a CDN URL for an asset","description":"Public assets return a direct CDN URL. Protected assets return a marker — call POST /assets/{id}/url for a time-limited signed URL.","operationId":"get_media_assets_by_id_resolve","responses":{"200":{"description":"Resolved URL or marker"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"transformClass","in":"query","schema":{"type":"string"},"description":"Optional Bunny image transform class."}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/resolve-urls":{"post":{"tags":["media"],"summary":"Resolve CDN URLs for up to 100 (assetId, transformClass) pairs","description":"Results are positionally aligned with `items` — a missing or hidden asset yields `null` in its slot rather than shifting the array.","operationId":"post_media_assets_resolve_urls","responses":{"200":{"description":"Resolved URLs or markers, one per requested item","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":["object","null"],"properties":{"url":{"type":["string","null"]},"requiresSignedUrl":{"type":"boolean"},"blurhash":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"variants":{"description":"Same-crop-geometry srcset candidates (ascending width), present on public assets with more than one rendition of the resolved framing.","type":"array","items":{"type":"object","required":["url","width"],"properties":{"url":{"type":"string"},"width":{"type":"integer"}}}}}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","maxItems":100,"items":{"type":"object","required":["assetId"],"properties":{"assetId":{"type":"string"},"transformClass":{"type":"string","enum":["thumb","card","hero","full","square"]}}}}}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/media/assets/by-ids":{"post":{"tags":["media"],"summary":"Batch-fetch up to 100 media assets by id","description":"Batch-fetch up to 100 media assets by id","operationId":"post_media_assets_by_ids","responses":{"200":{"description":"Matching assets (missing ids are omitted)"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string"},"maxItems":100}}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/schema":{"get":{"tags":["platform"],"summary":"Get app schema","description":"Get app schema","operationId":"get_platform_apps_by_slug_schema","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/artifact":{"put":{"tags":["platform"],"summary":"Write app artifact envelope","description":"Write app artifact envelope\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"put_platform_apps_by_slug_artifact","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"The expected base no longer matches the stored artifact; nothing was written","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["sdl","app-schema","function"]},"document":{"type":"string"},"def":{"type":"object"},"page":{"type":"string"},"fn":{"type":"string"},"function":{"type":"object"},"origin":{"type":"object","properties":{"source":{"type":"string","enum":["generation","refinement","manual","restore"]},"runId":{"type":"string"},"revision":{"type":"number"},"engine":{"type":"string","enum":["workflow","interactive"]}},"required":["source"]},"expected":{"type":"object","properties":{"version":{"type":"number"},"canonicalHash":{"type":"string"}}}},"required":["kind"]}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"get":{"tags":["platform"],"summary":"Get app artifact envelope (authoring)","description":"Get app artifact envelope (authoring)","operationId":"get_platform_apps_by_slug_artifact","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"string"}},{"name":"fn","in":"query","required":false,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/artifact/functions":{"get":{"tags":["platform"],"summary":"List stored function rows","description":"List stored function rows","operationId":"get_platform_apps_by_slug_artifact_functions","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/artifact/pages":{"get":{"tags":["platform"],"summary":"List SDL page rows","description":"List SDL page rows","operationId":"get_platform_apps_by_slug_artifact_pages","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/artifact/versions":{"get":{"tags":["platform"],"summary":"List artifact version snapshots","description":"List artifact version snapshots","operationId":"get_platform_apps_by_slug_artifact_versions","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"string"}},{"name":"fn","in":"query","required":false,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/artifact/versions/{version}":{"get":{"tags":["platform"],"summary":"Get one artifact version snapshot","description":"Get one artifact version snapshot","operationId":"get_platform_apps_by_slug_artifact_versions_by_version","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer"}},{"name":"page","in":"query","required":false,"schema":{"type":"string"}},{"name":"fn","in":"query","required":false,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/entities/{entity}":{"get":{"tags":["platform"],"summary":"List entity rows","description":"List entity rows","operationId":"get_platform_apps_by_slug_entities_by_entity","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"sort_key","in":"query","schema":{"type":"string"}},{"name":"sort_dir","in":"query","schema":{"type":"string","enum":["asc","desc"]}},{"name":"filters","in":"query","description":"Optional JSON-encoded filter array. Empty values are inactive; active filters use AND semantics and the DataTable operators contains, equals, not_equals, in, not_in, starts_with, and ends_with.","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["platform"],"summary":"Create entity row","description":"Create entity row\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_platform_apps_by_slug_entities_by_entity","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"object"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/entities/{entity}/{id}":{"get":{"tags":["platform"],"summary":"Get entity row","description":"Get entity row","operationId":"get_platform_apps_by_slug_entities_by_entity_by_id","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["platform"],"summary":"Update entity row","description":"Update entity row\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_platform_apps_by_slug_entities_by_entity_by_id","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"patch":{"type":"object"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["platform"],"summary":"Delete entity row","description":"Policy-aware removal. For trash-enabled entities this moves the row to managed trash (recoverable until purged); for hard-delete entities it removes permanently. The app schema declares which policy applies.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_platform_apps_by_slug_entities_by_entity_by_id","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/entities/{entity}/tombstones":{"get":{"tags":["platform"],"summary":"List entity trash","description":"List tombstones for a trash-enabled entity, newest deletion first. Requires read-trash.","operationId":"get_platform_apps_by_slug_entities_by_entity_tombstones","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"number"}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/entities/{entity}/tombstones/{tombstoneId}/restore":{"post":{"tags":["platform"],"summary":"Restore entity row from trash","description":"Conflict-safe restore: refused if a live row occupies the original key, if the snapshot no longer validates against the current schema, or if it references rows that no longer exist. The tombstone survives a refused restore.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_platform_apps_by_slug_entities_by_entity_tombstones_by_tombstoneId_restore","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"tombstoneId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/entities/{entity}/tombstones/{tombstoneId}":{"delete":{"tags":["platform"],"summary":"Purge entity tombstone","description":"Permanently remove a tombstone. Not implied by delete permission; requires purge.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_platform_apps_by_slug_entities_by_entity_tombstones_by_tombstoneId","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}},{"name":"tombstoneId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/platform/schema-info":{"get":{"tags":["platform"],"summary":"Introspect the Convex database schema","description":"Returns 403 if the caller lacks manage:database in dev-launcher.","operationId":"get_platform_schema_info","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/namespaces":{"get":{"tags":["platform"],"summary":"List manageable platform RBAC namespaces","description":"List manageable platform RBAC namespaces","operationId":"get_platform_namespaces","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps":{"post":{"tags":["platform"],"summary":"Create a platform-hosted app","description":"Create a platform-hosted app\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_platform_apps","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","displayName"],"properties":{"slug":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/platform/register":{"post":{"tags":["platform"],"summary":"Register an app namespace with RBAC","description":"Register an app namespace with RBAC\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_platform_register","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["appSlug","appInfo"]}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/platform/apps/{slug}/settings":{"patch":{"tags":["platform"],"summary":"Set a single app setting","description":"Set a single app setting\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_platform_apps_by_slug_settings","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key"],"properties":{"key":{"type":"string"},"value":{}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes":{"get":{"tags":["notes"],"summary":"List notes","description":"List active notes for the authenticated caller. `?titles=1` returns a lightweight id+title list; `?archived=1` returns archived notes instead. Content is encrypted client-side.","operationId":"get_notes","responses":{"200":{"description":"Notes (or titles when ?titles=1)","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Note"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"titles","in":"query","description":"When \"1\", return only {id,title}","schema":{"type":"string"}},{"name":"archived","in":"query","description":"When \"1\", list archived notes","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["notes"],"summary":"Create a note","description":"Create a note. `encryptedContent`/`iv`/`salt` must be produced by client-side AES-GCM; the server stores them opaquely.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notes","responses":{"201":{"description":"Created note","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Note"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","encryptedContent","iv","salt"],"properties":{"title":{"type":"string"},"encryptedContent":{"type":"string"},"iv":{"type":"string"},"salt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}":{"get":{"tags":["notes"],"summary":"Get a note","description":"Get a note","operationId":"get_notes_by_id","responses":{"200":{"description":"Note","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Note"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["notes"],"summary":"Update a note","description":"Patch fields. Omitted fields are unchanged. `metadata` here replaces the whole metadata object.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_notes_by_id","responses":{"200":{"description":"Updated note","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Note"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"encryptedContent":{"type":"string"},"iv":{"type":"string"},"salt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["notes"],"summary":"Delete a note permanently","description":"Delete a note permanently\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_notes_by_id","responses":{"200":{"description":"Deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}/metadata":{"patch":{"tags":["notes"],"summary":"Shallow-merge note metadata","description":"Shallow-merge note metadata\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_notes_by_id_metadata","responses":{"200":{"description":"Updated note","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Note"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata"],"properties":{"metadata":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}/touch":{"post":{"tags":["notes"],"summary":"Touch a note (bump frecency)","description":"Touch a note (bump frecency)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notes_by_id_touch","responses":{"200":{"description":"OK flag"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}/boost":{"post":{"tags":["notes"],"summary":"Boost a note","description":"Boost a note\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notes_by_id_boost","responses":{"200":{"description":"OK flag"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["durationMs"],"properties":{"durationMs":{"type":"integer","minimum":1}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}/unboost":{"post":{"tags":["notes"],"summary":"Remove a note boost","description":"Remove a note boost\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notes_by_id_unboost","responses":{"200":{"description":"OK flag"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}/archive":{"post":{"tags":["notes"],"summary":"Archive a note","description":"Archive a note\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notes_by_id_archive","responses":{"200":{"description":"OK flag"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notes/{id}/restore":{"post":{"tags":["notes"],"summary":"Restore an archived note","description":"Restore an archived note\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notes_by_id_restore","responses":{"200":{"description":"OK flag"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/roles":{"get":{"tags":["access"],"summary":"List role definitions for a namespace","description":"List role definitions for a namespace","operationId":"get_access_roles","responses":{"200":{"description":"Role definitions","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"appNamespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"adminNamespace","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["access"],"summary":"Define or update a role","description":"Create or update a role definition. Requires manage:roles in the namespace.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_roles","responses":{"200":{"description":"Role definition","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["appNamespace","roleName","permissions"],"properties":{"appNamespace":{"type":"string"},"roleName":{"type":"string"},"permissions":{"type":"array","items":{"type":"string"}},"description":{"type":"string"},"adminNamespace":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/users/{subject}/{aspect}":{"get":{"tags":["access"],"summary":"Get a user’s roles, direct permissions, or bundle","description":"aspect ∈ roles|permissions|bundle. Own is free; others require read:users.","operationId":"get_access_users_by_subject_by_aspect","responses":{"200":{"description":"RBAC data","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"oneOf":[{"type":"array","items":{"type":"object"}},{"type":"object"},{"type":"null"}]}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"subject","in":"path","required":true,"schema":{"type":"string"}},{"name":"aspect","in":"path","required":true,"schema":{"type":"string","enum":["roles","permissions","bundle"]}},{"name":"appNamespace","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/namespaces":{"get":{"tags":["access"],"summary":"List accessible app namespaces","description":"List accessible app namespaces","operationId":"get_access_namespaces","responses":{"200":{"description":"Namespace list","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/auth-events":{"get":{"tags":["access"],"summary":"Recent auth events","description":"Recent auth events","operationId":"get_access_auth_events","responses":{"200":{"description":"Auth events","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/alerts":{"get":{"tags":["access"],"summary":"List security alerts","description":"List security alerts","operationId":"get_access_alerts","responses":{"200":{"description":"Alerts","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/alerts/{id}":{"patch":{"tags":["access"],"summary":"Update alert status or ban from alert","description":"Update alert status or ban from alert\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_access_alerts_by_id","responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/bans":{"post":{"tags":["access"],"summary":"Issue a ban / suspension / warning","description":"Issue a ban / suspension / warning\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_bans","responses":{"201":{"description":"Ban issued","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/bans/{id}":{"delete":{"tags":["access"],"summary":"Revoke an active ban","description":"{id} is the ban id. Shares the path template with GET, where {id} is a user subject.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_access_bans_by_id","responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"get":{"tags":["access"],"summary":"List bans for a user","description":"{id} is the user subject. Shares the path template with DELETE, where {id} is a ban id.","operationId":"get_access_bans_by_id","responses":{"200":{"description":"Bans for the user","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/pats":{"get":{"tags":["access"],"summary":"List the caller’s personal access tokens","description":"Owner-scoped metadata for every PAT belonging to the calling user. Includes optional scope when the token was minted with least-privilege narrowing.","operationId":"get_access_pats","responses":{"200":{"description":"PAT metadata","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PatListEntry"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/subscribers":{"get":{"tags":["access"],"summary":"List subscribers","description":"List subscribers","operationId":"get_access_subscribers","responses":{"200":{"description":"Subscribers","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/subscribers/grant":{"post":{"tags":["access"],"summary":"Grant a complimentary subscription","description":"Grant a complimentary subscription\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_subscribers_grant","responses":{"200":{"description":"Granted","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/members/stats":{"get":{"tags":["access"],"summary":"Member stats over a window","description":"Member stats over a window","operationId":"get_access_members_stats","responses":{"200":{"description":"Member stats","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"days","in":"query","required":true,"schema":{"type":"integer"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/members/timeseries":{"get":{"tags":["access"],"summary":"Member count time series","description":"Member count time series","operationId":"get_access_members_timeseries","responses":{"200":{"description":"Member time series","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"days","in":"query","required":true,"schema":{"type":"integer"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/members/breakdown":{"get":{"tags":["access"],"summary":"Active members by subscription tier","description":"Active members by subscription tier","operationId":"get_access_members_breakdown","responses":{"200":{"description":"Member breakdown","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/members/recent-activity":{"get":{"tags":["access"],"summary":"Recently active members","description":"Recently active members","operationId":"get_access_members_recent_activity","responses":{"200":{"description":"Recent member activity","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"limit","in":"query","schema":{"type":"integer"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/roles/{name}":{"get":{"tags":["access"],"summary":"Get a role definition","description":"Get a role definition","operationId":"get_access_roles_by_name","responses":{"200":{"description":"Role definition","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":["object","null"]}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"appNamespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"adminNamespace","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"delete":{"tags":["access"],"summary":"Delete a role and strip it from all members","description":"Delete a role and strip it from all members\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_access_roles_by_name","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"appNamespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"adminNamespace","in":"query","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/roles/{name}/members":{"get":{"tags":["access"],"summary":"List the members holding a role","description":"List the members holding a role","operationId":"get_access_roles_by_name_members","responses":{"200":{"description":"Role members","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"appNamespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"adminNamespace","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/auth-events/stats":{"get":{"tags":["access"],"summary":"Auth-event stats","description":"Auth-event stats","operationId":"get_access_auth_events_stats","responses":{"200":{"description":"Auth-event stats","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"days","in":"query","schema":{"type":"integer"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/auth-events/by-user/{userId}":{"get":{"tags":["access"],"summary":"Auth-event history for a user","description":"Auth-event history for a user","operationId":"get_access_auth_events_by_user_by_userId","responses":{"200":{"description":"Auth events for the user","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/alerts/stats":{"get":{"tags":["access"],"summary":"Security alert stats","description":"Security alert stats","operationId":"get_access_alerts_stats","responses":{"200":{"description":"Alert stats","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/bans/active":{"get":{"tags":["access"],"summary":"List all active bans","description":"List all active bans","operationId":"get_access_bans_active","responses":{"200":{"description":"Active bans","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/subscribers/stats":{"get":{"tags":["access"],"summary":"Subscriber stats","description":"Subscriber stats","operationId":"get_access_subscribers_stats","responses":{"200":{"description":"Subscriber stats","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/subscribers/revoke":{"post":{"tags":["access"],"summary":"Revoke a complimentary subscription","description":"Revoke a complimentary subscription\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_subscribers_revoke","responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userSubject"],"properties":{"userSubject":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/gdpr/export":{"post":{"tags":["access"],"summary":"Request a GDPR data export (self-service)","description":"Request a GDPR data export (self-service)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_gdpr_export","responses":{"201":{"description":"Export requested","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"get":{"tags":["access"],"summary":"Get the caller’s GDPR export status","description":"Get the caller’s GDPR export status","operationId":"get_access_gdpr_export","responses":{"200":{"description":"Export status","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":["object","null"]}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/roles/{name}/{action}":{"post":{"tags":["access"],"summary":"Assign or revoke a role for a user","description":"action ∈ assign|revoke. Requires assign:roles in the namespace.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_roles_by_name_by_action","responses":{"200":{"description":"Assignment result","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"action","in":"path","required":true,"schema":{"type":"string","enum":["assign","revoke"]}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["appNamespace","userSubject"],"properties":{"appNamespace":{"type":"string"},"userSubject":{"type":"string"},"adminNamespace":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/users/{subject}/permissions":{"post":{"tags":["access"],"summary":"Grant a direct permission to a user","description":"Grant a direct permission to a user\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_access_users_by_subject_permissions","responses":{"201":{"description":"Permission granted","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"subject","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["appNamespace","permission"],"properties":{"appNamespace":{"type":"string"},"permission":{"type":"string"},"adminNamespace":{"type":"string"},"expiresAt":{"type":"integer","description":"Epoch ms; omit for no expiry"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/users/{subject}/permissions/{permission}":{"delete":{"tags":["access"],"summary":"Revoke a direct permission from a user","description":"Revoke a direct permission from a user\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_access_users_by_subject_permissions_by_permission","responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"subject","in":"path","required":true,"schema":{"type":"string"}},{"name":"permission","in":"path","required":true,"schema":{"type":"string"}},{"name":"appNamespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"adminNamespace","in":"query","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/access/users/by-subjects":{"post":{"tags":["access"],"summary":"Resolve subject ids to user records","description":"Resolve subject ids to user records","operationId":"post_access_users_by_subjects","responses":{"200":{"description":"Resolved users","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subjects"],"properties":{"subjects":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/users/search":{"get":{"tags":["access"],"summary":"Search users by email/name (security dashboard)","description":"Search users by email/name (security dashboard)","operationId":"get_access_users_search","responses":{"200":{"description":"Matching users","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/subscribers/search":{"get":{"tags":["access"],"summary":"Search users for a complimentary subscription grant","description":"Search users for a complimentary subscription grant","operationId":"get_access_subscribers_search","responses":{"200":{"description":"Matching users + subscription status","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/access/subscribers/stripe-prefix":{"get":{"tags":["access"],"summary":"Stripe dashboard URL prefix (test/live)","description":"Stripe dashboard URL prefix (test/live)","operationId":"get_access_subscribers_stripe_prefix","responses":{"200":{"description":"Prefix string","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"string"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/feature-flags":{"get":{"tags":["feature_flags"],"summary":"List feature flags","description":"List feature flags","operationId":"get_feature_flags","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["draft","active","archived"]}},{"name":"kind","in":"query","schema":{"type":"string","enum":["flag","entitlement","config"]}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["feature_flags"],"summary":"Create a feature flag","description":"Create a feature flag\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_feature_flags","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key","type","defaultValue","description"],"properties":{"key":{"type":"string"},"kind":{"type":"string","enum":["flag","entitlement","config"]},"type":{"type":"string","enum":["boolean","string","number","json"]},"defaultValue":{},"description":{"type":"string"},"rules":{"type":"array","items":{"type":"object"}},"experiment":{"type":"object"},"appNamespaces":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/feature-flags/{key}":{"get":{"tags":["feature_flags"],"summary":"Get a feature flag by key","description":"Get a feature flag by key","operationId":"get_feature_flags_by_key","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["feature_flags"],"summary":"Update a feature flag","description":"Update a feature flag\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_feature_flags_by_key","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/feature-flags/{key}/activate":{"patch":{"tags":["feature_flags"],"summary":"Activate a draft flag","description":"Activate a draft flag\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_feature_flags_by_key_activate","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/feature-flags/{key}/deactivate":{"patch":{"tags":["feature_flags"],"summary":"Deactivate a flag (kill-switch)","description":"Deactivate a flag (kill-switch)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_feature_flags_by_key_deactivate","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/feature-flags/{key}/archive":{"patch":{"tags":["feature_flags"],"summary":"Archive a flag (soft delete)","description":"Archive a flag (soft delete)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_feature_flags_by_key_archive","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found"},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/feature-flags/{key}/duplicate":{"patch":{"tags":["feature_flags"],"summary":"Duplicate a flag","description":"Duplicate a flag\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_feature_flags_by_key_duplicate","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newKey"],"properties":{"newKey":{"type":"string"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/ops/read/{operation}":{"post":{"tags":["ops"],"summary":"Run an ops read operation","description":"Supported operations: list_audit_log, search, get_index_health, admin_search, admin_search_all, get_api_usage, alerts_list, alerts_get, tasks_recent, tasks_stuck, task_crons_list, task_crons_supported_types","operationId":"post_ops_read_by_operation","responses":{"200":{"description":"Ops operation result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"operation","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/ops/write/{operation}":{"post":{"tags":["ops"],"summary":"Run an ops write operation","description":"Supported operations: alerts_create, alerts_update, alerts_activate, alerts_deactivate, alerts_delete, tasks_retrigger, task_crons_upsert, task_crons_set_enabled, task_crons_delete, task_crons_run_now\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_ops_write_by_operation","responses":{"200":{"description":"Ops operation result"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"operation","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notifications":{"get":{"tags":["notifications"],"summary":"List notification broadcasts","description":"List notification broadcasts","operationId":"get_notifications","responses":{"200":{"description":"Broadcasts, newest first"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["notifications"],"summary":"Create a draft broadcast","description":"Create a draft broadcast\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_notifications","responses":{"200":{"description":"New broadcast id"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notifications/{id}":{"get":{"tags":["notifications"],"summary":"Get a notification broadcast","description":"Get a notification broadcast","operationId":"get_notifications_by_id","responses":{"200":{"description":"Broadcast"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"patch":{"tags":["notifications"],"summary":"Update a draft broadcast","description":"Update a draft broadcast\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_notifications_by_id","responses":{"200":{"description":"Updated"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string"},"content":{"type":"object","description":"Optional static, display-only SDL detail. Keep body as the plain-text fallback.","properties":{"kind":{"type":"string","enum":["sdl"]},"document":{"type":"object"}},"required":["kind","document"]},"recipientSubjects":{"type":"array","items":{"type":"string"}},"actions":{"type":"array","items":{"type":"object"}}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]},"delete":{"tags":["notifications"],"summary":"Delete a draft notification broadcast","description":"Permanently deletes a draft. Sent broadcasts cannot be deleted.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"delete_notifications_by_id","responses":{"200":{"description":"Draft deleted"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notifications/{id}/send":{"patch":{"tags":["notifications"],"summary":"Send a draft broadcast","description":"Fans the broadcast out to all recipients and marks it sent.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"patch_notifications_by_id_send","responses":{"200":{"description":"Sent; returns recipientCount"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/notifications/users/search":{"get":{"tags":["notifications"],"summary":"Search users for broadcast recipients","description":"Search users by email/name (max 10 results). Returned `subject` values can be used as recipientSubjects.","operationId":"get_notifications_users_search","responses":{"200":{"description":"Matching users"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/notifications/users/by-subjects":{"post":{"tags":["notifications"],"summary":"Resolve a list of subjects to {subject,email,name}","description":"Resolve a list of subjects to {subject,email,name}","operationId":"post_notifications_users_by_subjects","responses":{"200":{"description":"Resolved users"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subjects"],"properties":{"subjects":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/health":{"get":{"tags":["embeddings"],"summary":"Embedding health for a namespace","description":"Embedding health for a namespace","operationId":"get_embeddings_health","responses":{"200":{"description":"Embedding health summary"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/docs":{"get":{"tags":["embeddings"],"summary":"List indexed + unindexed docs","description":"List indexed + unindexed docs","operationId":"get_embeddings_docs","responses":{"200":{"description":"Indexed + unindexed doc lists"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/active-task":{"get":{"tags":["embeddings"],"summary":"Active embedding task for a namespace","description":"Active embedding task for a namespace","operationId":"get_embeddings_active_task","responses":{"200":{"description":"Active task or null"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/chunks/{kvId}":{"get":{"tags":["embeddings"],"summary":"Embedded chunks for a KV doc","description":"Embedded chunks for a KV doc","operationId":"get_embeddings_chunks_by_kvId","responses":{"200":{"description":"Per-chunk text + model"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"kvId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/transcript/{videoId}":{"get":{"tags":["embeddings"],"summary":"Video transcript + smart actions","description":"Video transcript + smart actions","operationId":"get_embeddings_transcript_by_videoId","responses":{"200":{"description":"Transcript + smart actions + status"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"videoId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/search":{"post":{"tags":["embeddings"],"summary":"Semantic (vector) search","description":"Semantic (vector) search","operationId":"post_embeddings_search","responses":{"200":{"description":"Scored, deduped results"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["namespace","query"],"properties":{"namespace":{"type":"string"},"query":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":20}}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/generate":{"post":{"tags":["embeddings"],"summary":"Trigger embedding generation","description":"Trigger embedding generation\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_embeddings_generate","responses":{"200":{"description":"started | already_running with taskId"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["namespace"],"properties":{"namespace":{"type":"string"},"forceReEmbed":{"type":"boolean"}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/transcript/{videoId}/requeue":{"post":{"tags":["embeddings"],"summary":"Re-queue video transcription (fresh STT)","description":"Re-queue video transcription (fresh STT)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_embeddings_transcript_by_videoId_requeue","responses":{"200":{"description":"Queued"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"videoId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/transcript/{videoId}/requeue-smart":{"post":{"tags":["embeddings"],"summary":"Re-queue video smart actions (no re-STT)","description":"Re-queue video smart actions (no re-STT)\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_embeddings_transcript_by_videoId_requeue_smart","responses":{"200":{"description":"Queued"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"videoId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/transcript/{videoId}/save-edit":{"post":{"tags":["embeddings"],"summary":"Save a manual transcript edit","description":"Save a manual transcript edit\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_embeddings_transcript_by_videoId_save_edit","responses":{"200":{"description":"Saved"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"videoId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/embeddings/video-transcript-search":{"post":{"tags":["embeddings"],"summary":"Search video transcripts semantically","description":"Search video transcripts semantically","operationId":"post_embeddings_video_transcript_search","responses":{"200":{"description":"Search hits"},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/workflows/definitions":{"get":{"tags":["workflows"],"summary":"List workflow definitions","description":"List immutable workflow definition summaries in a namespace. Requires `read:workflow_definitions`.","operationId":"get_workflows_definitions","responses":{"200":{"description":"Paginated workflow definition summaries","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["page","isDone","continueCursor"],"properties":{"page":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowDefinitionSummary"}},"isDone":{"type":"boolean"},"continueCursor":{"type":"string"},"splitCursor":{"type":["string","null"]},"pageStatus":{"type":["string","null"],"enum":["SplitRecommended","SplitRequired",null]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/workflows/definitions/{key}/revisions/{revision}":{"get":{"tags":["workflows"],"summary":"Get a workflow revision","description":"Get one immutable, executable workflow revision. Requires `read:workflow_definitions`.","operationId":"get_workflows_definitions_by_key_revisions_by_revision","responses":{"200":{"description":"Workflow revision","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WorkflowDefinitionRevision"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"revision","in":"path","required":true,"schema":{"type":"integer","minimum":1}},{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/workflows/definitions/{key}/revisions":{"post":{"tags":["workflows"],"summary":"Publish a workflow revision","description":"Compile and publish a new immutable revision. The definition key must match the path key. Requires `manage:workflow_definitions`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_workflows_definitions_by_key_revisions","responses":{"201":{"description":"Published revision identifiers","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["definitionId","revisionId","revision"],"properties":{"definitionId":{"type":"string"},"revisionId":{"type":"string"},"revision":{"type":"integer","minimum":1}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["namespace","definition"],"properties":{"namespace":{"type":"string"},"definition":{"$ref":"#/components/schemas/WorkflowDefinition"},"displayName":{"type":"string"},"description":{"type":"string"},"retentionDays":{"type":"integer","minimum":1,"maximum":365,"default":30},"expectedLatestRevision":{"type":"integer","minimum":0,"description":"Optimistic concurrency guard. Use 0 when creating a definition."}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/workflows/runs":{"get":{"tags":["workflows"],"summary":"List workflow runs","description":"List runs in a namespace, optionally filtered by workflow key and lifecycle status. Requires `read:workflow_runs`.","operationId":"get_workflows_runs","responses":{"200":{"description":"Paginated workflow runs","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["page","isDone","continueCursor"],"properties":{"page":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowRun"}},"isDone":{"type":"boolean"},"continueCursor":{"type":"string"},"splitCursor":{"type":["string","null"]},"pageStatus":{"type":["string","null"],"enum":["SplitRecommended","SplitRequired",null]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}},{"name":"workflowKey","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["queued","running","waiting","completed","failed","canceled"]}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["workflows"],"summary":"Start a workflow run","description":"Start an asynchronous run pinned to a published revision. Returns 200 when an idempotency key reuses an existing run, otherwise 201. Requires `create:workflow_runs`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_workflows_runs","responses":{"200":{"description":"Existing idempotent run reused","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["run","reused"],"properties":{"run":{"$ref":"#/components/schemas/WorkflowRun"},"reused":{"type":"boolean"}}}}}}}},"201":{"description":"Workflow run started","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["run","reused"],"properties":{"run":{"$ref":"#/components/schemas/WorkflowRun"},"reused":{"type":"boolean"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["namespace","workflowKey","initialArtifact"],"properties":{"namespace":{"type":"string"},"workflowKey":{"type":"string"},"revision":{"type":"integer","minimum":1,"description":"Omit to use the latest published revision."},"initialArtifact":{"$ref":"#/components/schemas/WorkflowTextArtifactInput"},"idempotencyKey":{"type":"string","maxLength":256}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/workflows/runs/{runId}":{"get":{"tags":["workflows"],"summary":"Get a workflow run","description":"Get current state for one workflow run. Requires `read:workflow_runs`.","operationId":"get_workflows_runs_by_runId","responses":{"200":{"description":"Workflow run","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WorkflowRun"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/workflows/runs/{runId}/events":{"get":{"tags":["workflows"],"summary":"List workflow run events","description":"List the durable event timeline for a run. Requires `read:workflow_runs`.","operationId":"get_workflows_runs_by_runId_events","responses":{"200":{"description":"Paginated workflow run events","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["page","isDone","continueCursor"],"properties":{"page":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowRunEvent"}},"isDone":{"type":"boolean"},"continueCursor":{"type":"string"},"splitCursor":{"type":["string","null"]},"pageStatus":{"type":["string","null"],"enum":["SplitRecommended","SplitRequired",null]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]},"post":{"tags":["workflows"],"summary":"Send an event to a workflow run","description":"Resume a declared wait node with an immutable text artifact. Returns 200 when the idempotency key reuses an existing event, otherwise 201. Requires `send:workflow_events`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_workflows_runs_by_runId_events","responses":{"200":{"description":"Existing idempotent event reused","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["event","reused"],"properties":{"event":{"$ref":"#/components/schemas/WorkflowRunEvent"},"reused":{"type":"boolean"}}}}}}}},"201":{"description":"Workflow event delivered","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["event","reused"],"properties":{"event":{"$ref":"#/components/schemas/WorkflowRunEvent"},"reused":{"type":"boolean"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nodeId","eventName","artifact","idempotencyKey"],"properties":{"nodeId":{"type":"string"},"eventName":{"type":"string"},"artifact":{"$ref":"#/components/schemas/WorkflowTextArtifactInput"},"idempotencyKey":{"type":"string","minLength":1,"maxLength":256}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/workflows/runs/{runId}/artifacts":{"get":{"tags":["workflows"],"summary":"List workflow run artifacts","description":"List artifact metadata for a workflow run without payloads. Requires `read:workflow_artifacts`.","operationId":"get_workflows_runs_by_runId_artifacts","responses":{"200":{"description":"Paginated workflow artifact metadata","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["page","isDone","continueCursor"],"properties":{"page":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowArtifactSummary"}},"isDone":{"type":"boolean"},"continueCursor":{"type":"string"},"splitCursor":{"type":["string","null"]},"pageStatus":{"type":["string","null"],"enum":["SplitRecommended","SplitRequired",null]}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}},"/api/v1/workflows/runs/{runId}/cancel":{"post":{"tags":["workflows"],"summary":"Cancel a workflow run","description":"Cancel a non-terminal workflow run. Cancellation is cooperative for actions already in flight. Requires `manage:workflow_runs`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_workflows_runs_by_runId_cancel","responses":{"200":{"description":"Canceled workflow run","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WorkflowRun"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/workflows/runs/{runId}/restart":{"post":{"tags":["workflows"],"summary":"Restart a workflow run from a parallel boundary","description":"Restart a failed run from a parallel node declared by its pinned revision. A required idempotency key makes retries safe; `reused` reports whether the prior restart was returned. Arbitrary component step names are rejected. Requires `manage:workflow_runs`.\n\nSend `Idempotency-Key` to make a write retryable. The key is bound to the HTTP method, concrete path and query, and raw request body. Reusing it for a different request returns 400 with `code: idempotency_key_reuse`. A matching request that is still running returns 409 with `code: idempotency_in_progress` and `Retry-After: 5`; retry after that delay. Successful 2xx responses are replayable for 24 hours and include `Idempotency-Replayed: true` on replay. If the original response exceeds 256 KiB, later retries return 409 with `code: idempotency_replay_unavailable` instead of running the write again. Non-2xx responses are not retained.","operationId":"post_workflows_runs_by_runId_restart","responses":{"200":{"description":"New or reused idempotent workflow restart","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["run","reused"],"properties":{"run":{"$ref":"#/components/schemas/WorkflowRun"},"reused":{"type":"boolean"}}}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency state conflict. Use the response `code` to distinguish `idempotency_in_progress` from `idempotency_replay_unavailable`; `Retry-After` is present only while the original request is running.","headers":{"Retry-After":{"description":"Seconds to wait before retrying an in-progress request","schema":{"type":"integer","const":5}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional key for safely retrying this write. Keys are scoped to the platform service caller or to the PAT user (all PATs for one user share a scope).","schema":{"type":"string","minLength":1,"maxLength":256}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parallelNodeId","idempotencyKey"],"properties":{"parallelNodeId":{"type":"string"},"idempotencyKey":{"type":"string","minLength":1,"maxLength":256}}}}}},"security":[{"bearerAuth":["api:write"]},{"oauth2":["full"]}]}},"/api/v1/workflows/artifacts/{artifactId}":{"get":{"tags":["workflows"],"summary":"Get a workflow artifact","description":"Get artifact metadata and the immutable text payload. The core bounds payload size to 256 KiB. Requires `read:workflow_artifacts`.","operationId":"get_workflows_artifacts_by_artifactId","responses":{"200":{"description":"Workflow artifact and text payload","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/WorkflowArtifactResult"}}}}}},"400":{"description":"Bad request — invalid arguments or path","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Authenticated but lacks the required permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Seconds until the request may be retried","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"name":"artifactId","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["api:read"]},{"oauth2":["full"]}]}}},"tags":[{"name":"system","description":"Cross-cutting auth and identity endpoints."},{"name":"me","description":""},{"name":"tasks","description":"Task-list CRUD: create, list, move between status columns, archive, attachments."},{"name":"kvark","description":""},{"name":"content","description":"Content pages and nav trees: create, publish, version, reorder, access gates."},{"name":"content_layouts","description":""},{"name":"communications","description":""},{"name":"ledger","description":"Ledger bookkeeping: journal entries, customers, time, invoices, reports, attachments, and integrations."},{"name":"analytics","description":"Per-namespace analytics reads — overview, time series, top paths/referrers."},{"name":"studio","description":""},{"name":"marozzo","description":"Marozzo assistant — non-streaming chat turns and thread history."},{"name":"dictionaries","description":"Dual-lane search across Florio (1611) and Crusca (1612) historical Italian dictionaries."},{"name":"hero_promos","description":""},{"name":"media","description":""},{"name":"platform","description":""},{"name":"notes","description":""},{"name":"access","description":""},{"name":"feature_flags","description":""},{"name":"ops","description":""},{"name":"notifications","description":""},{"name":"embeddings","description":""},{"name":"workflows","description":"Immutable workflow definitions and durable run control: publish, start, inspect, cancel, restart, events, and artifacts."}]}