{"openapi":"3.1.0","info":{"title":"Libot Cloud Services API","description":"REST API for managing data contracts (ODCS — Open Data Contract Standard) and data products (ODPS — Open Data Product Standard). Part of the Bitol ecosystem by jgp.ai.\n\nHandles user management, contract validation and transformation (YAML, DDL, PDF), contract comparison with semver impact analysis, maturity assessment, lifecycle tracking, reference tags, Credits (API credit) system, GitHub Actions integration, and data product generation.\n\n## The two documentation groups\n\nThe dropdown at the top of this page offers **User API**, **Admin API** and **Deprecated API**. They are three views of one API, not three APIs.\n\nAll three cover **v1, v2, v3 and v4 identically** — same paths, same servers, same authentication. The only difference is which operations are listed:\n\n- **User API** — the current surface, minus the admin-only operations. This is the default view, the one you are looking at unless you changed the dropdown.\n- **Admin API** — the same, **plus** the admin-only operations.\n- **Deprecated API** — every deprecated operation, and nothing else.\n\nIn other words, **Admin API is User API plus the admin-only operations** — a superset, not a parallel surface. Nothing current is in User API but missing from Admin API. Go straight there with [`/admin-ui.html`](/admin-ui.html).\n\nTogether the three groups **partition** the API: every operation is in exactly one of them, nothing is documented twice and nothing is lost.\n\n**Deprecated endpoints still work.** They moved to their own group so the current surface reads cleanly, not because anything about them changed. If an endpoint you already call is missing from User API, look in Deprecated API before assuming it is gone. If you are writing something new, use `/v4`.\n\nA small set of owner-only integrity operations is documented in **none** of the three. They exist and they work; they are simply not published here.\n\n## Authentication\n\nThis API supports two authentication mechanisms depending on the endpoint version:\n\n### V2/V3/V4 endpoints — Bearer JWT via OAuth 2.1 (recommended)\n\nModern endpoints accept Bearer JWTs minted by the Bitol authorization server.\nFirst-party and third-party clients obtain tokens through the OAuth 2.1\nauthorization-code + PKCE flow:\n\n**Step 1 — Redirect the user to:**\n\n```\nGET /oauth2/authorize\n  ?response_type=code\n  &client_id=<your-client-id>\n  &redirect_uri=<your-redirect-uri>\n  &code_challenge=<S256(verifier)>\n  &code_challenge_method=S256\n  &scope=openid\n```\n\n**Step 2 — Exchange the returned code for tokens:**\n\n```\nPOST /oauth2/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code\n&code=<code>\n&redirect_uri=<your-redirect-uri>\n&code_verifier=<verifier>\n&client_id=<your-client-id>\n```\n\n**Step 3 — Use the token in subsequent requests:**\n\n```\nAuthorization: Bearer <accessToken>\n```\n\n**Step 4 — Refresh before expiry via `POST /oauth2/token` with\n`grant_type=refresh_token`.**\n\nThe previous bespoke `/v2/auth/{login,refresh,logout,verify,register,signup-request}`\nand `/v3/auth/device-code{,/poll,/confirm}` surfaces were removed in v7. Stale\nclients hitting those URLs receive HTTP 410 with a typed\n`LEGACY_AUTH_DEACTIVATED` envelope pointing at the replacements.\n\n### V1 endpoints — API Key + Password headers\n\nLegacy V1 endpoints authenticate via two custom headers sent together:\n- `X-API-KEY` — UUID obtained during user registration or via `GET /v1/users/key`\n- `X-USER-PASSWORD` — the user's plaintext password (verified server-side via BCrypt)\n\n### Public endpoints (no authentication required)\n\n- `GET /signin` — AS-hosted credential form (entry point for /oauth2/authorize)\n- `POST /oauth2/token` — OAuth 2.1 token endpoint (authorization‐code, refresh‐token)\n- `POST /v4/users/register` — Create a new account\n- `POST /v4/users/verify` — Verify email with the activation code\n- `POST /v4/users/signup-request` — Request to join (Grand Opening queue)\n- `POST /v1/users` — Create a new user (V1)\n- `GET /v1/validate` — Activate account with email code\n- `GET /v1/health` — Health check\n- `POST /v1/diagnostics` — Submit front-end error report\n\n### Admin endpoints\n\nSome endpoints require admin privileges. The authenticated user must have the `admin` flag set in their account. Admin endpoints are only visible in the **Admin API** group — switch the dropdown at the top of this page, or open [`/admin-ui.html`](/admin-ui.html) directly. They are absent from the default **User API** view, so a missing endpoint there is a documentation choice, not evidence that it does not exist.\n\n## Limitations\n\n- **Email addresses** must not contain a `+` character.\n- **Blocked email domains** (registration): gmail.com, yahoo.com, hotmail.com, outlook.com, aol.com, protonmail.com, icloud.com, mail.com, yandex.com, live.com, msn.com, gmx.com, zoho.com, tutanota.com, pm.me.\n- **Contract files** must have an `.odcs.yaml` extension.\n- **Product files** must have an `.odps.yaml` extension.\n- **Logo files** must be valid SVG (content must start with `<svg` or contain the SVG namespace URI).\n- **DDL subformat**: only `PostgreSQL` is currently supported.","contact":{"name":"Jean-Georges Perrin","url":"https://jgp.ai","email":"jgp@jgp.ai"},"license":{"name":"Proprietary"},"version":"9.117.15"},"servers":[{"url":"https://api.jgp.ai","description":"Production"},{"url":"http://localhost:8080","description":"Local development"}],"security":[{"ApiKeyAuth":[],"PasswordAuth":[]}],"tags":[{"name":"Publishing","description":"Logo upload and PDF rendering settings (v4 copy of /v2 publishing — #560 AC-4)"},{"name":"Artifacts","description":"Unified artifact listing across contracts and products"},{"name":"Admin","description":"Administration of the AI interaction log"},{"name":"Users","description":"User registration, email verification, authentication, and profile management"},{"name":"Interactions","description":"Records a user interaction with an AI-suggested artifact — accepted, rejected, or edited"},{"name":"Membership","description":"Organization membership management (param-form org addressing — #651)"},{"name":"Administration","description":"Service health check with optional Bearer JWT authentication"},{"name":"Products","description":"Data product endpoints with Bearer JWT authentication"},{"name":"Organization Settings","description":"Organization logo and PDF rendering settings"},{"name":"Products","description":"V3 data product CRUD endpoints with unified org context"},{"name":"Comments","description":"Comments and task assignment on artifacts"},{"name":"Templates","description":"V4 catalog of pre-built ODCS contract templates"},{"name":"Signing","description":"Signing key and certificate management"},{"name":"Products","description":"Data product creation, upload, and retrieval (ODPS)"},{"name":"Credits","description":"API credit balance, transactions, usage tracking, redemption, and cost management (#871)"},{"name":"Comments","description":"Comments and task assignment on artifacts (v4, experimental)"},{"name":"Users","description":"User registration, authentication, profile management, and administration"},{"name":"Organization Contracts","description":"Organization-scoped data contract endpoints (v4 copy of /v2 — #560 AC-4)"},{"name":"Diagnostics","description":"Test-run story steps (screenshots + timeline) — #712"},{"name":"Onboarding","description":"Onboarding funnel tracking (#1007)"},{"name":"Contact Sync","description":"Sync external contacts to the marketing platform"},{"name":"Lifecycle","description":"Artifact lifecycle tracking with Bearer JWT authentication"},{"name":"Badges","description":"Achievement badges"},{"name":"GitHub Crawl Import","description":"Experimental deterministic derivation of contracts/products from Teradata ETL in GitHub"},{"name":"Contact Sync","description":"Sync external contacts to MailerLite"},{"name":"Membership","description":"Organization membership management"},{"name":"Organization Settings","description":"Organization-scoped integration defaults"},{"name":"Podemites","description":"The reward currency: earned on credit consumption, never spent"},{"name":"Maturity History","description":"Maturity distribution history over time (v4 copy of /v3/maturity-history — #560 AC-4)"},{"name":"Organization Contracts","description":"Organization-scoped data contract endpoints with Bearer JWT authentication"},{"name":"Lifecycle","description":"Artifact lifecycle tracking for contracts and products"},{"name":"Organization Settings","description":"Organization settings — logo, PDF configuration, GitHub token, integrations, domain management"},{"name":"Automation","description":"Workflow installation, secrets management, and GitHub Actions triggering"},{"name":"Publishing","description":"Integration credential management for external platforms"},{"name":"Public Profiles","description":"Read another Workbench user's public profile by handle (#1215)"},{"name":"Contracts","description":"Data contract endpoints with Bearer JWT authentication"},{"name":"Users","description":"User accounts"},{"name":"Data Sources","description":"Reusable named JDBC data-source credentials for contract test execution (#718)"},{"name":"External Catalogs","description":"Browse external data catalogs and import datasets as contracts (v4 copy of /v3/catalogs — #560 AC-4)"},{"name":"Administration","description":"Admin-only endpoints — users, activity logs, email logs, feature flags, onboarding funnel, health"},{"name":"Organization Contracts","description":"Organization-scoped data contract endpoints"},{"name":"Users","description":"User lifecycle: register, verify email, request to join"},{"name":"Contracts","description":"Data contract upload, retrieval, and format conversion (ODCS)"},{"name":"Administration","description":"Admin-only endpoints"},{"name":"Publishing","description":"Logo upload and PDF rendering settings with Bearer JWT authentication"},{"name":"DDL","description":"SQL DDL generation from data contracts and data products"},{"name":"Tags","description":"Reference tags and tag cloud for data contracts and products"},{"name":"Users","description":"User profile endpoints with Bearer JWT authentication"},{"name":"Organization Plugins","description":"Organization-registered plugins (svc#1131)"},{"name":"Presence","description":"Active viewers of contracts and products"},{"name":"Administration","description":"Admin-only endpoints — global feature flags (#1022)"},{"name":"Publishing","description":"Logo upload, PDF rendering settings, and publishing credentials for external platforms"},{"name":"Organization Settings","description":"Organization-scoped GitHub integration defaults (param-form org addressing — #651)"},{"name":"Credits","description":"v2 Credits routes for the iOS surface"},{"name":"Products","description":"Data product management (ODPS)"},{"name":"Demo","description":"Import or refresh the Demo Customer 360 example (#1418)"},{"name":"Publishing","description":"Integration credential management for external platforms (v4 copy of /v2 — #560 AC-4)"},{"name":"Organizations","description":"Organization management with Bearer JWT authentication"},{"name":"Tags","description":"Reference tags and tag cloud (v4)"},{"name":"Publishing","description":"Integration defaults for publishing to external platforms"},{"name":"Organization Settings","description":"Organization-scoped integration management"},{"name":"Administration","description":"Admin-only endpoints — per-org feature configuration (#1025)"},{"name":"Publishing","description":"Logo upload and PDF rendering settings"},{"name":"Organization Products","description":"Organization-scoped data product endpoints (v4 copy of /v2 — #560 AC-4)"},{"name":"External Catalogs","description":"Browse external data catalogs and import datasets as contracts"},{"name":"AI","description":"AI text-suggestion proxy for the Workbench"},{"name":"Lifecycle","description":"V3 artifact lifecycle tracking with org context"},{"name":"Administration","description":"Admin-only endpoints with Bearer JWT authentication"},{"name":"Administration","description":"Admin-only endpoints — onboarding funnel (#1007)"},{"name":"Publishing","description":"Integration defaults for publishing to external platforms (v4 copy of /v2 — #560 AC-4)"},{"name":"Diagnostics","description":"Front-end error reporting and admin review"},{"name":"Service Accounts","description":"Org-owned OAuth2 machine identities (client_credentials grant) for CI/CD — #197"},{"name":"Self-Report","description":"In-app problem reports from the Workbench Help rail and the anonymous /report page"},{"name":"Automation","description":"Workflow installation, secrets management, and Actions triggering"},{"name":"Interactions","description":"Record a user interaction with an AI-suggested artifact — accepted, rejected, or edited"},{"name":"Organization Products","description":"Organization-scoped data product endpoints with Bearer JWT authentication"},{"name":"Diagnostics","description":"Front-end error reporting and admin review (v4 copy of /v1/diagnostics — #560 AC-3d)"},{"name":"Administration","description":"Admin-only endpoints — the plugin kill switch (svc#1132)"},{"name":"Contracts","description":"Data contract endpoints with enhanced GitHub publishing (v3)"},{"name":"Credits","description":"Organization Credits management"},{"name":"Users","description":"User profile endpoints (v4 copy of /v2 users — #560 AC-4)"},{"name":"Public Profiles","description":"Read another Workbench user's public profile by handle. Requires a JWT — \"public\" means visible to signed-in platform users, not to the open internet — and there is deliberately no way to list or search profiles (#1215)"},{"name":"Membership","description":"Organization membership management with Bearer JWT authentication"},{"name":"Maturity History","description":"V3 maturity distribution history over time"},{"name":"Administration","description":"Admin-only endpoints for activity logs and system monitoring"},{"name":"Contact Sync","description":"Sync external contacts to MailerLite (v4)"},{"name":"Maturity History","description":"Maturity distribution history over time"},{"name":"Diagnostics","description":"Front-end error reporting, admin review, and test-run story steps"},{"name":"AI","description":"V4 AI text-suggestion proxy for the Workbench"},{"name":"Import","description":"Bulk import of ODCS/ODPS artifacts from a ZIP archive"},{"name":"Organization Products","description":"Organization-scoped data product endpoints"},{"name":"Organization Agent Providers","description":"Organization-registered A2A agent providers (#961)"},{"name":"Credits","description":"Admin Credits management"},{"name":"Notifications","description":"Per-user notification feed derived from comments and task assignments"},{"name":"Administration","description":"Admin-only endpoints — the demo set's fleet-wide push (#1470)"},{"name":"Tags","description":"V4 tag cloud and counts (org-aware)"},{"name":"Products","description":"Data product endpoints with enhanced GitHub publishing (v3)"},{"name":"Artifacts","description":"V4 unified artifact listing (contracts + products)"},{"name":"Contracts","description":"V3 data contract CRUD endpoints with unified org context"},{"name":"Organization Settings","description":"Organization logo and PDF rendering settings (param-form org addressing — #651)"},{"name":"Automation","description":"Workflow installation, secrets management, and Actions triggering (v4)"},{"name":"Lifecycle","description":"Artifact lifecycle tracking for contracts and products (v4)"},{"name":"Credits","description":"API credit management"},{"name":"Templates","description":"Catalog of pre-built ODCS contract templates"},{"name":"Platform","description":"Global platform feature flags (#1022)"},{"name":"Demo","description":"Import or refresh the Demo Customer 360 example from the live demo organization (#1418). Gated on the demoImportRefresh platform feature"},{"name":"GitHub Crawl Import","description":"Crawl a GitHub repository and import the artifacts it holds"},{"name":"Administration","description":"V4 health check with Bearer JWT authentication (#569)"},{"name":"Maturity Model","description":"Read-only maturity-model definitions (levels + criteria) for contracts and products"},{"name":"Admin","description":"Platform administration"},{"name":"Organizations","description":"Organization management (param-form org addressing — #651)"},{"name":"Organization Settings","description":"Organization-scoped integration management (param-form org addressing — #651)"},{"name":"Signing","description":"Signing key and certificate management (v4)"},{"name":"Organizations","description":"Organization management — create, discover, search, update, delete"},{"name":"Administration","description":"Admin-only endpoints (v4 copy of /v2 admin — #560 AC-4)"},{"name":"Verification","description":"Public signature verification (no authentication required)"}],"paths":{"/v4/users/me/integrations/{key}":{"put":{"tags":["Publishing"],"summary":"Store integration credentials","description":"**Since v7.6.0** — Sets credentials for the specified integration (github, zeenea, or controlcenter).","operationId":"setCredentials","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Credentials saved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.update","description":"Store integration credentials"}],"x-since":"7.6.0"},"delete":{"tags":["Publishing"],"summary":"Remove integration credentials","description":"**Since v7.6.0** — Clears all fields for the specified integration. Defaults are preserved.","operationId":"removeCredentials","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.delete","description":"Remove integration credentials"}],"x-since":"7.6.0"}},"/v4/users/me/integrations/github/defaults":{"get":{"tags":["Publishing"],"summary":"Get GitHub defaults","description":"**Since v7.6.0** — Returns the user's configured GitHub publishing defaults.","operationId":"getDefaults","responses":{"200":{"description":"Current defaults","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.get","description":"Get GitHub publishing defaults"}],"x-since":"7.6.0"},"put":{"tags":["Publishing"],"summary":"Set GitHub defaults","description":"**Since v7.6.0** — Configures default repository, branch, commit message template, and auto-publish flag for GitHub publishing.","operationId":"setDefaults","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubDefaultsRequest"}}},"required":true},"responses":{"200":{"description":"Defaults configured","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.update","description":"Set GitHub publishing defaults"}],"x-since":"7.6.0"},"delete":{"tags":["Publishing"],"summary":"Reset GitHub defaults","description":"**Since v7.6.0** — Clears all GitHub publishing defaults for the authenticated user.","operationId":"resetDefaults","responses":{"200":{"description":"Defaults cleared","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.delete","description":"Reset GitHub publishing defaults"}],"x-since":"7.6.0"}},"/v4/reference-tags/{tagName}":{"get":{"tags":["Tags"],"summary":"Get a reference tag (v4, born-deprecated)","description":"**Since v7.1.3** — Returns details of a specific reference tag. Verbatim copy of /v1/reference-tags/{tagName}.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getTag","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.get","description":"Get a reference tag"}],"x-since":"7.1.3","x-sunset":"2027-01-01"},"put":{"tags":["Tags"],"summary":"Update a reference tag (v4, born-deprecated)","description":"**Since v7.1.3** — Updates the properties and/or description of an existing reference tag. Verbatim copy of PUT /v1/reference-tags/{tagName}.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateTag","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":false,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.update","description":"Update a reference tag"}],"x-since":"7.1.3","x-sunset":"2027-01-01"},"delete":{"tags":["Tags"],"summary":"Delete a reference tag (v4, born-deprecated)","description":"**Since v7.1.3** — Deletes a reference tag. Verbatim copy of DELETE /v1/reference-tags/{tagName}.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteTag","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.delete","description":"Delete a reference tag"}],"x-since":"7.1.3","x-sunset":"2027-01-01"}},"/v4/reference-tags/{tagName}/apply-changes":{"put":{"tags":["Tags"],"summary":"Apply tag changes (v4, born-deprecated)","description":"**Since v7.1.3** — Applies reference tag changes to selected artifacts with specified versions. Verbatim copy of PUT /v1/reference-tags/{tagName}/apply-changes.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"applyChanges","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string","default":""}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.changes.apply","description":"Apply reference tag changes to artifacts"}],"x-since":"7.1.3","x-sunset":"2027-01-01"}},"/v4/reference-tags/{tagName}/analyze-impact":{"put":{"tags":["Tags"],"summary":"Analyze tag impact (v4, born-deprecated)","description":"**Since v7.1.3** — Analyzes which artifacts would be affected by changing this reference tag. Verbatim copy of PUT /v1/reference-tags/{tagName}/analyze-impact.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"analyzeImpact","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.impact.analyze","description":"Analyze the impact of changing a reference tag"}],"x-since":"7.1.3","x-sunset":"2027-01-01"}},"/v4/products/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a product lifecycle entry (v4, born-deprecated)","description":"**Since v7.1.6** — Verbatim copy of PUT /v1/products/lifecycle/{id}.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateProductLifecycleEntry","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.product.update","description":"Edit a product lifecycle entry"}],"x-since":"7.1.6","x-sunset":"2027-01-01"}},"/v4/orgs":{"get":{"tags":["Organizations"],"summary":"Get organization","description":"**Since v7.26.0** — Returns organization details including associated domains. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"getOrg","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Organization details","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.get","description":"Get an organization by slug"}],"x-since":"7.26.0"},"put":{"tags":["Organizations"],"summary":"Update organization","description":"**Since v7.26.0** — Updates organization details (name, phone, address, etc.). Slug cannot be changed. Pass org (slug) or orgId (UUID) to select the organization. `publicCompany` (#1212) controls whether the organization may be named publicly; omitting it leaves it unchanged, unlike the address fields which are last-write-wins.","operationId":"updateOrg","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"phone","in":"query","required":false,"schema":{"type":"string"}},{"name":"address","in":"query","required":false,"schema":{"type":"string"}},{"name":"city","in":"query","required":false,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"postalCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"publicCompany","in":"query","description":"#1212 — whether the organization may be named publicly, on its members' public profiles and on its own public page. Omit to leave unchanged; the other fields here are last-write-wins, this one deliberately is not.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Organization updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or invalid update","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.update","description":"Update organization details"}],"x-since":"7.26.0"},"post":{"tags":["Organizations"],"summary":"Create an organization","description":"**Since v7.7.0** — Creates a new organization with the given name, slug, and optional domains. The authenticated user becomes the creator.","operationId":"createOrg","parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string"}},{"name":"slug","in":"query","required":true,"schema":{"type":"string"}},{"name":"domains","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Organization created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid slug, duplicate slug, or domain already claimed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.create","description":"Create a new organization"}],"x-since":"7.7.0"},"delete":{"tags":["Organizations"],"summary":"Delete organization (owner or platform-admin)","description":"**Since v7.26.0** — Deletes an organization: Keycloak group (detaching all members), membership rows, domains, pending invitations/join-requests, Credit balance (forfeited), and the org row; the org's artifact storage is archived (moved aside, never destroyed) — #182/TD-2. A platform admin may delete any organization. An org OWNER may delete their own organization only when it is empty — no members other than the owner, and no contracts or products; a non-empty owner delete is refused with 409 (#854). Pass org (slug) or orgId (UUID).","operationId":"deleteOrg","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Organization deleted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is neither the org owner nor a platform admin","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Owner delete refused — organization is not empty","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.delete","description":"Delete an organization (owner or platform-admin)"}],"x-since":"7.26.0"}},"/v4/orgs/{slug}":{"get":{"tags":["Organizations"],"summary":"Get organization by slug (deprecated slug path)","description":"**Since v7.7.0** — Returns organization details including associated domains. Deprecated — use GET /v4/orgs with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getOrgBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization details","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"},"put":{"tags":["Organizations"],"summary":"Update organization (deprecated slug path)","description":"**Since v7.7.0** — Updates organization details (name, phone, address, etc.). Slug cannot be changed. Deprecated — use PUT /v4/orgs with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateOrgBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"phone","in":"query","required":false,"schema":{"type":"string"}},{"name":"address","in":"query","required":false,"schema":{"type":"string"}},{"name":"city","in":"query","required":false,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"postalCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"publicCompany","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Organization updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organizations"],"summary":"Delete organization (owner or platform-admin, deprecated slug path)","description":"**Since v7.7.0** — Deletes an organization: Keycloak group (detaching all members), membership rows, domains, pending invitations/join-requests, Credit balance (forfeited), and the org row; the org's artifact storage is archived (moved aside, never destroyed) — #182/TD-2. Same authorization as DELETE /v4/orgs: platform-admin (any org) or the org OWNER (empty org only, else 409). Deprecated — use DELETE /v4/orgs with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteOrgBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is neither the org owner nor a platform admin","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Owner delete refused — organization is not empty","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/transfer-ownership":{"put":{"tags":["Membership"],"summary":"Transfer organization ownership (deprecated slug path)","description":"**Since v7.11.0** — Owner atomically transfers ownership to an existing member of the same organization. Caller is demoted to MEMBER and the target user is promoted to OWNER in a single transaction. Required before a sole owner can leave the org or delete their account. Deprecated — use PUT /v4/orgs/transfer-ownership with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"transferOwnershipBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOwnershipRequest"}}},"required":true},"responses":{"200":{"description":"Ownership transferred","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"New owner is not a member of the org, or invalid payload","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an owner of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or target user not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/messages/{messageId}/reject":{"put":{"tags":["Membership"],"summary":"Reject a join request (deprecated slug path)","description":"**Since v7.11.0** — Admin/owner rejects a pending join request. Deprecated — use PUT /v4/orgs/messages/{messageId}/reject with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"rejectBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Join request rejected","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found or not pending","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/messages/{messageId}/decline":{"put":{"tags":["Membership"],"summary":"Decline an invitation (deprecated slug path)","description":"**Since v7.11.0** — The invited user declines the invitation. Deprecated — use PUT /v4/orgs/messages/{messageId}/decline with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"declineBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation declined","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found, not pending, or wrong user","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/messages/{messageId}/approve":{"put":{"tags":["Membership"],"summary":"Approve a join request (deprecated slug path)","description":"**Since v7.11.0** — Admin/owner approves a pending join request. The user becomes a MEMBER. Deprecated — use PUT /v4/orgs/messages/{messageId}/approve with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"approveBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Join request approved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found or not pending","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/messages/{messageId}/accept":{"put":{"tags":["Membership"],"summary":"Accept an invitation (deprecated slug path)","description":"**Since v7.11.0** — The invited user accepts. They become a MEMBER of the organization. Deprecated — use PUT /v4/orgs/messages/{messageId}/accept with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"acceptBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation accepted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found, not pending, or wrong user","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/members/{userId}/role":{"put":{"tags":["Membership"],"summary":"Change a member's role (deprecated slug path)","description":"**Since v7.11.0** — Owner changes a member's role. Only owners can promote to admin. Deprecated — use PUT /v4/orgs/members/{userId}/role with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"changeRoleBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"role","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot demote last owner","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/integrations/{key}":{"put":{"tags":["Organization Settings"],"summary":"Store org integration credentials (deprecated slug path)","description":"**Since v7.10.0** — Stores credentials for an org integration. Requires ADMIN+ role. Deprecated — use PUT /v4/orgs/integrations/{key} with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setCredentialsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Credentials saved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Settings"],"summary":"Remove org integration credentials (deprecated slug path)","description":"**Since v7.10.0** — Removes the credentials of an org integration. Requires ADMIN+ role. Deprecated — use DELETE /v4/orgs/integrations/{key} with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeCredentialsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/integrations/github/defaults":{"get":{"tags":["Organization Settings"],"summary":"Get org GitHub defaults (deprecated slug path)","description":"**Since v7.10.0** — Returns the organization's configured GitHub publishing defaults. Requires org membership. Deprecated — use GET /v4/orgs/integrations/github/defaults with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getDefaultsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Current defaults","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"},"put":{"tags":["Organization Settings"],"summary":"Set org GitHub defaults (deprecated slug path)","description":"**Since v7.10.0** — Configures default repository, branch, commit message template, and auto-publish flag for the organization. Requires ADMIN+ role. Deprecated — use PUT /v4/orgs/integrations/github/defaults with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setDefaultsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubDefaultsRequest"}}},"required":true},"responses":{"200":{"description":"Defaults configured","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Settings"],"summary":"Reset org GitHub defaults (deprecated slug path)","description":"**Since v7.10.0** — Clears all GitHub publishing defaults for the organization. Requires ADMIN+ role. Deprecated — use DELETE /v4/orgs/integrations/github/defaults with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"resetDefaultsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Defaults cleared","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/github-token":{"put":{"tags":["Organizations"],"summary":"Set organization GitHub token (deprecated slug path)","description":"**Since v7.7.0** — Encrypts and stores a GitHub token for the organization. Requires OWNER role. Deprecated — use PUT /v4/orgs/github-token with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setGithubTokenBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GitHub token set","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (OWNER required)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organizations"],"summary":"Remove organization GitHub token (deprecated slug path)","description":"**Since v7.7.0** — Removes the organization's stored GitHub token. Requires OWNER role. Deprecated — use DELETE /v4/orgs/github-token with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeGithubTokenBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GitHub token removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (OWNER required)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"}},"/v4/orgs/transfer-ownership":{"put":{"tags":["Membership"],"summary":"Transfer organization ownership","description":"**Since v7.26.0** — Owner atomically transfers ownership to an existing member of the same organization. Caller is demoted to MEMBER and the target user is promoted to OWNER in a single transaction. Required before a sole owner can leave the org or delete their account. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"transferOwnership","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOwnershipRequest"}}},"required":true},"responses":{"200":{"description":"Ownership transferred","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, new owner is not a member of the org, or invalid payload","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an owner of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or target user not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.transfer","description":"Transfer organization ownership"}],"x-since":"7.26.0"}},"/v4/orgs/plugins/{pluginId}/settings":{"get":{"tags":["Organization Plugins"],"summary":"Read my plugin settings","description":"**Since v9.4.0** — The caller's own configuration for one org-activated plugin. Secret values are never returned — the response reports only which secrets are set, because masking is a UI concern and the browser has no use for the bytes. Requires org membership.","operationId":"getSettings","parameters":[{"name":"pluginId","in":"path","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ pluginId, values, secrets }","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or no such plugin here","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.settings.get","description":"Read the caller's own settings for a plugin"}],"x-since":"9.4.0"},"put":{"tags":["Organization Plugins"],"summary":"Save my plugin settings","description":"**Since v9.4.0** — Upserts the caller's configuration. Body: {\"values\": {\"<key>\": \"<value>\"}}. Validated against the manifest's declared fields: an undeclared key is rejected and a required field must end up non-empty. Omitting a secret preserves the stored value; sending it as an empty string clears it. Requires org membership.","operationId":"saveSettings","parameters":[{"name":"pluginId","in":"path","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"The settings after saving, secrets still withheld","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Undeclared key, or a required field left empty","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or no such plugin here","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.settings.save","description":"Save the caller's own settings for a plugin"}],"x-since":"9.4.0"}},"/v4/orgs/messages/{messageId}/reject":{"put":{"tags":["Membership"],"summary":"Reject a join request","description":"**Since v7.26.0** — Admin/owner rejects a pending join request. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"reject","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Join request rejected","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, message not found, or not pending","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.reject","description":"Reject a join request"}],"x-since":"7.26.0"}},"/v4/orgs/messages/{messageId}/decline":{"put":{"tags":["Membership"],"summary":"Decline an invitation","description":"**Since v7.26.0** — The invited user declines the invitation. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"decline","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation declined","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, message not found, not pending, or wrong user","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.decline","description":"Decline an organization invitation"}],"x-since":"7.26.0"}},"/v4/orgs/messages/{messageId}/approve":{"put":{"tags":["Membership"],"summary":"Approve a join request","description":"**Since v7.26.0** — Admin/owner approves a pending join request. The user becomes a MEMBER. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"approve","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Join request approved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, message not found, or not pending","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.approve","description":"Approve a join request"}],"x-since":"7.26.0"}},"/v4/orgs/messages/{messageId}/accept":{"put":{"tags":["Membership"],"summary":"Accept an invitation","description":"**Since v7.26.0** — The invited user accepts. They become a MEMBER of the organization. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"accept","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation accepted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, message not found, not pending, or wrong user","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.accept","description":"Accept an organization invitation"}],"x-since":"7.26.0"}},"/v4/orgs/members/{userId}/role":{"put":{"tags":["Membership"],"summary":"Change a member's role","description":"**Since v7.26.0** — Owner changes a member's role. Only owners can promote to admin. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"changeRole","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"role","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or cannot demote last owner","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.update","description":"Change a member's role"}],"x-since":"7.26.0"}},"/v4/orgs/integrations/{key}":{"put":{"tags":["Organization Settings"],"summary":"Store org integration credentials","description":"**Since v7.26.0** — Stores credentials for an org integration. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"setCredentials_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Credentials saved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.update","description":"Store org integration credentials"}],"x-since":"7.26.0"},"delete":{"tags":["Organization Settings"],"summary":"Remove org integration credentials","description":"**Since v7.26.0** — Removes the credentials of an org integration. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"removeCredentials_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Integration removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.delete","description":"Remove org integration credentials"}],"x-since":"7.26.0"}},"/v4/orgs/integrations/github/defaults":{"get":{"tags":["Organization Settings"],"summary":"Get org GitHub defaults","description":"**Since v7.26.0** — Returns the organization's configured GitHub publishing defaults. Pass org (slug) or orgId (UUID) to select the organization. Requires org membership.","operationId":"getDefaults_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Current defaults","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.get","description":"Get org GitHub publishing defaults"}],"x-since":"7.26.0"},"put":{"tags":["Organization Settings"],"summary":"Set org GitHub defaults","description":"**Since v7.26.0** — Configures default repository, branch, commit message template, and auto-publish flag for the organization. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"setDefaults_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubDefaultsRequest"}}},"required":true},"responses":{"200":{"description":"Defaults configured","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.update","description":"Set org GitHub publishing defaults"}],"x-since":"7.26.0"},"delete":{"tags":["Organization Settings"],"summary":"Reset org GitHub defaults","description":"**Since v7.26.0** — Clears all GitHub publishing defaults for the organization. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"resetDefaults_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Defaults cleared","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.delete","description":"Reset org GitHub publishing defaults"}],"x-since":"7.26.0"}},"/v4/orgs/github-token":{"put":{"tags":["Organizations"],"summary":"Set organization GitHub token","description":"**Since v7.26.0** — Encrypts and stores a GitHub token for the organization. Requires OWNER role. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"setGithubToken","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GitHub token set","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (OWNER required)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.github-token.update","description":"Set the organization GitHub token"}],"x-since":"7.26.0"},"delete":{"tags":["Organizations"],"summary":"Remove organization GitHub token","description":"**Since v7.26.0** — Removes the organization's stored GitHub token. Requires OWNER role. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"removeGithubToken","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"GitHub token removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (OWNER required)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.github-token.delete","description":"Remove the organization GitHub token"}],"x-since":"7.26.0"}},"/v4/notifications/read":{"put":{"tags":["Notifications"],"summary":"Mark all notifications read","description":"**Since v7.23.0** — Sets the caller's mark-all-read watermark to now; a subsequent list shows unreadCount 0 for all existing items.","operationId":"markAllRead","responses":{"200":{"description":"Watermark updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"notifications.read-all","description":"Mark all of the caller's notifications read"}],"x-since":"7.23.0"}},"/v4/notifications/announcements/{announcementId}/dismiss":{"put":{"tags":["Notifications"],"summary":"Dismiss a platform announcement","description":"**Since v9.103.0** — Hides one platform announcement for the calling user, permanently. **Idempotent** — dismissing one that is already dismissed is a success, not a duplicate and not an error, because a client retrying after a dropped response should not see a failure for reaching the state it wanted.\n\nPer user: dismissing does not affect anybody else, and it survives a re-read — without that the message would reappear on every page load (#1471 AC-4).","operationId":"dismissAnnouncement","parameters":[{"name":"announcementId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Dismissed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid credentials","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such announcement","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"announcement.dismiss","description":"Dismiss a platform announcement"}],"x-since":"9.103.0"}},"/v4/diagnostics/{id}":{"get":{"tags":["Diagnostics"],"summary":"Get a single diagnostics report (admin only)","description":"**Since v7.1.1**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Full report","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid Bearer JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"diagnostics.get","description":"Get a single diagnostics report"}],"x-since":"7.1.1","x-sunset":"2027-01-01"},"put":{"tags":["Diagnostics"],"summary":"Update a diagnostics report (additive merge)","description":"**Since v7.1.1** — Unauthenticated. Fills null fields, concatenates JSONB arrays. Sets reportType to 'user'.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-CLI-KEY","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsReportRequest"}}},"required":true},"responses":{"200":{"description":"Report updated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Report not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"x-intent":[{"name":"diagnostics.update","description":"Additive merge update of a diagnostics report"}],"x-since":"7.1.1","x-sunset":"2027-01-01"},"patch":{"tags":["Diagnostics"],"summary":"Resolve or reopen a diagnostics report (admin only)","description":"**Since v7.1.1**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"resolve","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsResolveRequest"}}},"required":true},"responses":{"200":{"description":"Report updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid Bearer JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"diagnostics.resolve","description":"Resolve or reopen a diagnostics report"}],"x-since":"7.1.1","x-sunset":"2027-01-01"}},"/v4/data-sources/{name}":{"put":{"tags":["Data Sources"],"summary":"Create or overwrite a named data source","description":"**Since v7.35.0** — Stores the JDBC coordinates and password for a reusable data source. The password is encrypted at rest (AES-256-GCM) and never returned. Pass org or orgId for an org-shared data source.","operationId":"store","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}},"required":true},"responses":{"200":{"description":"Data source stored (no secret material in the response)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing connection parameters","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"datasource.store","description":"Create or overwrite a named data source"}],"x-since":"7.35.0"},"delete":{"tags":["Data Sources"],"summary":"Delete a named data source","description":"**Since v7.35.0** — Removes a named data source from the caller's scope. Contract-server bindings that referenced it will then fail to resolve until re-pointed.","operationId":"delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Data source deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such data source","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"datasource.delete","description":"Delete a named data source"}],"x-since":"7.35.0"}},"/v4/credits/bonuses/{code}":{"put":{"tags":["Credits"],"summary":"Update a gamification bonus (admin)","description":"**Since v7.44.0** — Updates the user bonus, org bonus, and/or enabled flag for a gamification bonus code. Admin only.","operationId":"updateBonus","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Bonus updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Bonus code not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.bonus.update","description":"Update a gamification bonus (admin)"}],"x-since":"7.44.0"},"delete":{"tags":["Credits"],"summary":"Delete a gamification bonus (admin)","description":"**Since v7.44.0** — Deletes the gamification bonus identified by its code. Admin only.","operationId":"deleteBonus","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bonus deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Bonus code not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.bonus.delete","description":"Delete a gamification bonus (admin)"}],"x-since":"7.44.0"}},"/v4/contracts/{contractId}/jdbc-credentials":{"put":{"tags":["Contracts"],"summary":"Store JDBC credentials for on-demand contract refresh","description":"**Since v7.33.0** — Stores (or overwrites) the JDBC connection parameters for a database-sourced contract version. The password is encrypted at rest (AES-256-GCM) and is never returned by any endpoint. Pass org or orgId for organization contracts. When version is omitted, the contract's latest version is used.","operationId":"storeCredentials","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"server","in":"query","description":"Contract servers[].server name this binding is for; omit for the default","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}},"required":true},"responses":{"200":{"description":"Credentials stored (no secret material in the response)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing connection parameters","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.refresh.credentials.store","description":"Store JDBC credentials for contract refresh"}],"x-since":"7.33.0"},"delete":{"tags":["Contracts"],"summary":"Delete stored JDBC credentials for a contract","description":"**Since v7.33.0** — Removes the stored JDBC connection parameters for a contract version. Subsequent refresh calls return 404 until credentials are stored again. When version is omitted, the contract's latest version is used.","operationId":"deleteCredentials","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"server","in":"query","description":"Contract servers[].server name; omit for the default binding","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Credentials deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract, organization, or stored credentials not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.refresh.credentials.delete","description":"Delete stored JDBC credentials"}],"x-since":"7.33.0"}},"/v4/contracts/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a contract lifecycle entry (v4, born-deprecated)","description":"**Since v7.1.6** — Verbatim copy of PUT /v1/contracts/lifecycle/{id}.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateContractLifecycleEntry","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.contract.update","description":"Edit a contract lifecycle entry"}],"x-since":"7.1.6","x-sunset":"2027-01-01"}},"/v4/comments/{id}":{"put":{"tags":["Comments"],"summary":"Edit a comment","description":"**Since v5.0.0** — Edit the body of a comment. Only the author can edit, and only the last message in a thread can be edited.","operationId":"editComment","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Comment updated","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not the author","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled or comment not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Not the last message in the thread","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.update","description":"Edit a comment body"}],"x-since":"5.0.0"},"delete":{"tags":["Comments"],"summary":"Delete a comment","description":"**Since v5.0.0** — Soft-deletes a comment. If the comment is top-level, all replies are also soft-deleted. Deleted comments appear in since-polling responses.","operationId":"deleteComment","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Comment deleted","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled or comment not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.delete","description":"Delete a comment"}],"x-since":"5.0.0"}},"/v4/comments/{id}/unresolve":{"put":{"tags":["Comments"],"summary":"Unresolve a comment thread","description":"**Since v5.0.0** — Removes the resolved status from a top-level comment thread.","operationId":"unresolveThread","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Thread unresolved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot unresolve a reply","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled or comment not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.thread.unresolve","description":"Unresolve a comment thread"}],"x-since":"5.0.0"}},"/v4/comments/{id}/resolve":{"put":{"tags":["Comments"],"summary":"Resolve a comment thread","description":"**Since v5.0.0** — Marks a top-level comment thread as resolved.","operationId":"resolveThread","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Thread resolved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot resolve a reply","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled or comment not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.thread.resolve","description":"Resolve a comment thread"}],"x-since":"5.0.0"}},"/v4/comments/tasks/{mentionId}/complete":{"put":{"tags":["Comments"],"summary":"Mark a task as completed","description":"**Since v5.0.0** — Marks a task assignment as completed. Only the assignee can complete it.","operationId":"completeTask","parameters":[{"name":"mentionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Task completed","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not the assignee","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled or mention not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.task.update","description":"Mark a comment task as completed"}],"x-since":"5.0.0"}},"/v4/badges/{awardId}/seen":{"put":{"tags":["Badges"],"summary":"Mark a badge award seen","description":"**Since v9.11.0** — Acknowledges one award so it stops appearing in `/v4/badges/unseen`. `PUT` rather than `POST` because marking seen is idempotent and the client may retry — a second call is still 204 and leaves the original timestamp alone. An award belonging to another user returns 404 rather than 403: confirming that someone else's award exists is itself a disclosure.","operationId":"markSeen","parameters":[{"name":"awardId","in":"path","description":"Award id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Acknowledged"},"401":{"description":"Missing or invalid JWT"},"404":{"description":"No such award for this caller"}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.award.mark-seen","description":"Acknowledge a badge award"}],"x-since":"9.11.0"}},"/v4/badges/templates/{id}":{"put":{"tags":["Badges"],"summary":"Update a badge template (admin)","description":"**Since v9.15.0** — Edits a badge in place. `id` is never changed — `badge_award` rows reference it, so renaming it would orphan every award of that badge. Existing awards are otherwise untouched by an edit: badges are never revoked. Omitted fields keep their stored values, and a partial update is validated against the values that will actually be in force.","operationId":"update_1","parameters":[{"name":"id","in":"path","description":"Badge id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadgeTemplateRequest"}}},"required":true},"responses":{"200":{"description":"Updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such template","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.template.update","description":"Update a badge template (admin)"}],"x-since":"9.15.0"}},"/v4/admin/users/admin":{"put":{"tags":["Administration"],"summary":"Set a user's admin flag (v4 admin)","description":"**Since v7.43.4** — Promotes or demotes a user by email: body `{\"admin\": true|false}`. Admin-only; evicts the target's auth cache so the change is immediate. An admin cannot remove their own admin flag (400). The v1 `PUT /users` profile-update path does not honor `admin`; this is the endpoint for admin promotion/demotion (#760).","operationId":"setUserAdmin","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Admin flag updated; returns the updated AdminUserResponse","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AdminUserResponse"}}}},"400":{"description":"Missing `admin` field, or admin attempted self-demotion","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.set-admin","description":"Set or unset a user's admin flag (admin)"}],"x-since":"7.43.4"}},"/v3/products/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a product lifecycle entry (v3)","description":"**Since v3.1.4** — Updates the comment on a product lifecycle entry. Pass org or orgId for org-scoped entries.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateProductLifecycleEntry_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Entry updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Entry not found, not owned by user, or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.product.update","description":"Edit a product lifecycle entry"}],"x-since":"3.1.4","x-sunset":"2027-01-01"}},"/v3/contracts/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a contract lifecycle entry (v3)","description":"**Since v3.1.4** — Updates the comment on a contract lifecycle entry. Pass org or orgId for org-scoped entries.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateContractLifecycleEntry_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Entry updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Entry not found, not owned by user, or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.contract.update","description":"Edit a contract lifecycle entry"}],"x-since":"3.1.4","x-sunset":"2027-01-01"}},"/v2/users/me/integrations/{key}":{"put":{"tags":["Publishing"],"summary":"Store integration credentials","description":"**Since v2.12.0** — Sets credentials for the specified integration (github, zeenea, or controlcenter).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setCredentials_2","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Credentials saved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.update","description":"Store integration credentials"}],"x-since":"2.12.0","x-sunset":"2027-01-01"},"delete":{"tags":["Publishing"],"summary":"Remove integration credentials","description":"**Since v2.12.0** — Clears all fields for the specified integration. Defaults are preserved.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeCredentials_2","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.delete","description":"Remove integration credentials"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/users/me/integrations/github/defaults":{"get":{"tags":["Publishing"],"summary":"Get GitHub defaults","description":"**Since v2.10.0** — Returns the user's configured GitHub publishing defaults.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getDefaults_2","responses":{"200":{"description":"Current defaults","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.get","description":"Get GitHub publishing defaults"}],"x-since":"2.10.0","x-sunset":"2027-01-01"},"put":{"tags":["Publishing"],"summary":"Set GitHub defaults","description":"**Since v2.10.0** — Configures default repository, branch, commit message template, and auto-publish flag for GitHub publishing.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setDefaults_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubDefaultsRequest"}}},"required":true},"responses":{"200":{"description":"Defaults configured","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.update","description":"Set GitHub publishing defaults"}],"x-since":"2.10.0","x-sunset":"2027-01-01"},"delete":{"tags":["Publishing"],"summary":"Reset GitHub defaults","description":"**Since v2.10.0** — Clears all GitHub publishing defaults for the authenticated user.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"resetDefaults_2","responses":{"200":{"description":"Defaults cleared","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.delete","description":"Reset GitHub publishing defaults"}],"x-since":"2.10.0","x-sunset":"2027-01-01"}},"/v2/reference-tags/{tagName}":{"get":{"tags":["Tags"],"summary":"Get a reference tag (v2)","description":"**Since v2.4.2** — Returns details of a specific reference tag\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getTag_1","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reference tag details","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.get","description":"Get a reference tag"}],"x-since":"2.4.2","x-sunset":"2027-01-01"},"put":{"tags":["Tags"],"summary":"Update a reference tag (v2)","description":"**Since v2.4.2** — Updates the properties and/or description of an existing reference tag\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateTag_1","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":false,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.update","description":"Update a reference tag"}],"x-since":"2.4.2","x-sunset":"2027-01-01"},"delete":{"tags":["Tags"],"summary":"Delete a reference tag (v2)","description":"**Since v2.4.2** — Deletes a reference tag\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteTag_1","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Tag deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.delete","description":"Delete a reference tag"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/reference-tags/{tagName}/apply-changes":{"put":{"tags":["Tags"],"summary":"Apply tag changes (v2)","description":"**Since v2.4.2** — Applies reference tag changes to selected artifacts with specified versions\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"applyChanges_1","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string","default":""}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Changes applied successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.changes.apply","description":"Apply reference tag changes to artifacts"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/reference-tags/{tagName}/analyze-impact":{"put":{"tags":["Tags"],"summary":"Analyze tag impact (v2)","description":"**Since v2.4.2** — Analyzes which artifacts would be affected by changing this reference tag\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"analyzeImpact_1","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Impact analysis result","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.impact.analyze","description":"Analyze the impact of changing a reference tag"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/products/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a product lifecycle entry (v2)","description":"**Since v2.2.0** — Deprecated — use PUT /v3/products/lifecycle/{id} instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateProductLifecycleEntry_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Entry updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Entry not found or not owned by user","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.product.update","description":"Edit a product lifecycle entry"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}":{"get":{"tags":["Organizations"],"summary":"Get organization by slug","description":"**Since v2.3.0** — Returns organization details including associated domains.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getOrg_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization details","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.get","description":"Get an organization by slug"}],"x-since":"2.3.0","x-sunset":"2027-01-01"},"put":{"tags":["Organizations"],"summary":"Update organization","description":"**Since v2.3.0** — Updates organization details (name, phone, address, etc.). Slug cannot be changed.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateOrg_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"phone","in":"query","required":false,"schema":{"type":"string"}},{"name":"address","in":"query","required":false,"schema":{"type":"string"}},{"name":"city","in":"query","required":false,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"postalCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"publicCompany","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Organization updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.update","description":"Update organization details"}],"x-since":"2.3.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organizations"],"summary":"Delete organization (platform-admin only)","description":"**Since v2.3.0** — Deletes an organization and its domains, Credit balance. Platform admin required.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteOrg_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.delete","description":"Delete an organization (admin only)"}],"x-since":"2.3.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/transfer-ownership":{"put":{"tags":["Membership"],"summary":"Transfer organization ownership","description":"**Since v7.0.23** — Owner atomically transfers ownership to an existing member of the same organization. Caller is demoted to MEMBER and the target user is promoted to OWNER in a single transaction. Required before a sole owner can leave the org or delete their account.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"transferOwnership_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOwnershipRequest"}}},"required":true},"responses":{"200":{"description":"Ownership transferred","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"New owner is not a member of the org, or invalid payload","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an owner of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or target user not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.transfer","description":"Transfer organization ownership"}],"x-since":"7.0.23","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/messages/{messageId}/reject":{"put":{"tags":["Membership"],"summary":"Reject a join request","description":"**Since v2.5.0** — Admin/owner rejects a pending join request.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"reject_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Join request rejected","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found or not pending","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.reject","description":"Reject a join request"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/messages/{messageId}/decline":{"put":{"tags":["Membership"],"summary":"Decline an invitation","description":"**Since v2.5.0** — The invited user declines the invitation.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"decline_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation declined","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found, not pending, or wrong user","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.decline","description":"Decline an organization invitation"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/messages/{messageId}/approve":{"put":{"tags":["Membership"],"summary":"Approve a join request","description":"**Since v2.5.0** — Admin/owner approves a pending join request. The user becomes a MEMBER.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"approve_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Join request approved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found or not pending","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.approve","description":"Approve a join request"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/messages/{messageId}/accept":{"put":{"tags":["Membership"],"summary":"Accept an invitation","description":"**Since v2.5.0** — The invited user accepts. They become a MEMBER of the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"accept_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation accepted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found, not pending, or wrong user","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.accept","description":"Accept an organization invitation"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/members/{userId}/role":{"put":{"tags":["Membership"],"summary":"Change a member's role","description":"**Since v2.5.0** — Owner changes a member's role. Only owners can promote to admin.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"changeRole_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"role","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot demote last owner","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.update","description":"Change a member's role"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/integrations/{key}":{"put":{"tags":["Organization Settings"],"summary":"Store org integration credentials","description":"**Since v2.12.0**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setCredentials_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Credentials saved","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.update","description":"Store org integration credentials"}],"x-since":"2.12.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Settings"],"summary":"Remove org integration credentials","description":"**Since v2.12.0**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeCredentials_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.delete","description":"Remove org integration credentials"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/integrations/github/defaults":{"get":{"tags":["Organization Settings"],"summary":"Get org GitHub defaults","description":"**Since v2.10.0** — Returns the organization's configured GitHub publishing defaults.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getDefaults_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Current defaults","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.get","description":"Get org GitHub publishing defaults"}],"x-since":"2.10.0","x-sunset":"2027-01-01"},"put":{"tags":["Organization Settings"],"summary":"Set org GitHub defaults","description":"**Since v2.10.0** — Configures default repository, branch, commit message template, and auto-publish flag for the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setDefaults_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubDefaultsRequest"}}},"required":true},"responses":{"200":{"description":"Defaults configured","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.update","description":"Set org GitHub publishing defaults"}],"x-since":"2.10.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Settings"],"summary":"Reset org GitHub defaults","description":"**Since v2.10.0** — Clears all GitHub publishing defaults for the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"resetDefaults_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Defaults cleared","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.defaults.delete","description":"Reset org GitHub publishing defaults"}],"x-since":"2.10.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/github-token":{"put":{"tags":["Organizations"],"summary":"Set organization GitHub token","description":"**Since v2.7.0** — Encrypts and stores a GitHub token for the organization. Requires OWNER role.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setGithubToken_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GitHub token set","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (OWNER required)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.github-token.update","description":"Set the organization GitHub token"}],"x-since":"2.7.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organizations"],"summary":"Remove organization GitHub token","description":"**Since v2.7.0** — Removes the organization's stored GitHub token. Requires OWNER role.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeGithubToken_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GitHub token removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (OWNER required)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.github-token.delete","description":"Remove the organization GitHub token"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/contracts/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a contract lifecycle entry (v2)","description":"**Since v2.2.0** — Deprecated — use PUT /v3/contracts/lifecycle/{id} instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updateContractLifecycleEntry_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Entry updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Entry not found or not owned by user","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.contract.update","description":"Edit a contract lifecycle entry"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v1/users":{"get":{"tags":["Users"],"summary":"List all users (admin only)","description":"**Since v1.0.0** — Returns all registered users with full details (except password hash). Restricted to admin users.","operationId":"listUsers","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of AdminUserResponse objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.list","description":"List all users (admin only)"}],"x-since":"1.0.0"},"put":{"tags":["Users"],"summary":"Update user profile","description":"**Since v1.0.0** — Updates profile fields: first name, last name, company, date of birth, comment. Password cannot be changed. Users can update their own profile; admins can update any user.","operationId":"updateUser","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Updated UserResponse","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (placeholder values)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Access denied (not own profile and not admin)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.update","description":"Update a user's profile"}],"x-since":"1.0.0"},"post":{"tags":["Users"],"summary":"Create a new user","description":"**Since v1.0.0** — Registers a new user account. A validation email with a 6-character code is sent to the provided email address. No authentication required.","operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreateRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully, returns UserResponse with API key","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (bad email, placeholder values, missing fields)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Email already registered","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.create","description":"Register a new user account"}],"x-since":"1.0.0"},"delete":{"tags":["Users"],"summary":"Delete a user (admin only)","description":"**Since v1.0.0** — Deletes a user by email. The user data is backed up to the user_backup table before deletion.","operationId":"delete_1","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"User successfully deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.delete","description":"Delete a user by email (admin only)"}],"x-since":"1.0.0"}},"/v1/users/password":{"put":{"tags":["Users"],"summary":"Change password","description":"**Since v2.1.4** — Changes a user's password. Regular users must provide currentPassword. Admins can change any user's password via email param without currentPassword.","operationId":"changePassword","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Password changed successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (missing or too short password)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid credentials or current password mismatch","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required for changing another user's password","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Target user not found (admin flow)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.change-password","description":"Change a user's password"}],"x-since":"2.1.4"}},"/v1/reference-tags/{tagName}":{"get":{"tags":["Tags"],"summary":"Get a reference tag","description":"**Since v1.0.0** — Returns details of a specific reference tag","operationId":"getTag_2","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reference tag details","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.get","description":"Get a reference tag"}],"x-since":"1.0.0"},"put":{"tags":["Tags"],"summary":"Update a reference tag","description":"**Since v1.0.0** — Updates the properties and/or description of an existing reference tag","operationId":"updateTag_2","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":false,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.update","description":"Update a reference tag"}],"x-since":"1.0.0"},"delete":{"tags":["Tags"],"summary":"Delete a reference tag","description":"**Since v1.0.0** — Deletes a reference tag","operationId":"deleteTag_2","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Tag deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.delete","description":"Delete a reference tag"}],"x-since":"1.0.0"}},"/v1/reference-tags/{tagName}/apply-changes":{"put":{"tags":["Tags"],"summary":"Apply tag changes","description":"**Since v1.0.0** — Applies reference tag changes to selected artifacts with specified versions","operationId":"applyChanges_2","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Changes applied successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.changes.apply","description":"Apply reference tag changes to artifacts"}],"x-since":"1.0.0"}},"/v1/reference-tags/{tagName}/analyze-impact":{"put":{"tags":["Tags"],"summary":"Analyze tag impact","description":"**Since v1.0.0** — Analyzes which artifacts would be affected by changing this reference tag","operationId":"analyzeImpact_2","parameters":[{"name":"tagName","in":"path","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Impact analysis result","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Tag not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.impact.analyze","description":"Analyze the impact of changing a reference tag"}],"x-since":"1.0.0"}},"/v1/products/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a product lifecycle entry","description":"**Since v1.0.0** — Updates the comment on a product lifecycle entry. Tracks all edits in an append-only audit trail.","operationId":"updateProductLifecycleEntry_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Entry updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Entry not found or not owned by user","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"lifecycle.product.update","description":"Edit a product lifecycle entry"}],"x-since":"1.0.0"}},"/v1/diagnostics/{id}":{"get":{"tags":["Diagnostics"],"summary":"Get a single diagnostics report (admin only)","description":"**Since v3.1.0**","operationId":"getById_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-CLI-KEY","in":"header","required":false,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Full report","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"diagnostics.get","description":"Get a single diagnostics report"}],"x-since":"3.1.0"},"put":{"tags":["Diagnostics"],"summary":"Update a diagnostics report (additive merge)","description":"**Since v3.1.0** — Unauthenticated. Fills null fields, concatenates JSONB arrays. Sets reportType to 'user'.","operationId":"update_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsReportRequest"}}},"required":true},"responses":{"200":{"description":"Report updated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Report not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"diagnostics.update","description":"Additive merge update of a diagnostics report"}],"x-since":"3.1.0"},"patch":{"tags":["Diagnostics"],"summary":"Resolve or reopen a diagnostics report (admin only)","description":"**Since v3.1.0**","operationId":"resolve_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-CLI-KEY","in":"header","required":false,"schema":{"type":"string","default":""}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsResolveRequest"}}},"required":true},"responses":{"200":{"description":"Report updated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"diagnostics.resolve","description":"Resolve or reopen a diagnostics report"}],"x-since":"3.1.0"}},"/v1/contracts/lifecycle/{id}":{"put":{"tags":["Lifecycle"],"summary":"Edit a contract lifecycle entry","description":"**Since v1.0.0** — Updates the comment on a contract lifecycle entry. Tracks all edits in an append-only audit trail.","operationId":"updateContractLifecycleEntry_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Entry updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Entry not found or not owned by user","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"lifecycle.contract.update","description":"Edit a contract lifecycle entry"}],"x-since":"1.0.0"}},"/v4/users/verify":{"post":{"tags":["Users"],"summary":"Verify email address","description":"**Since v7.0.0** — Verifies a user's email using the 6-character code sent during registration.","operationId":"verify","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V2VerifyRequest"}}},"required":true},"responses":{"200":{"description":"Email verified","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid verification code","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.validate","description":"Verify a user's email address with a code"}],"x-since":"7.0.0"}},"/v4/users/signup-request":{"post":{"tags":["Users"],"summary":"Submit a request to join Workbench","description":"**Since v7.0.0** — Public endpoint — anyone can request access. Rate-limited per IP. Optionally accepts a visitorId (the onboarding-funnel beacon key, #1007): when present, the anonymous visitor journey is stitched onto the email's journey via the request_submitted funnel event.","operationId":"signupRequest","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"201":{"description":"Request submitted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Email already has a full account (error=already_registered; body includes signinUrl — the trusted webapp sign-in page) or a still-pending request (error=duplicate_pending; the pending request's notify counter is bumped and admins are re-notified). A latest request that was rejected or expired does NOT 409 — a fresh pending request is created (201) and the admin notification mentions the prior outcome (#1003).","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Rate limit exceeded","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.signup-request.create","description":"Submit a request to join Workbench"}],"x-since":"7.0.0"}},"/v4/users/resend-verification":{"post":{"tags":["Users"],"summary":"Resend verification email (fresh code)","description":"**Since v8.16.5** — Public endpoint. Regenerates the account's email-verification code and emails it (bypassing the marketing/integrity ban gate, like password reset). Anti-enumeration: always returns 200 with a generic message — including for unknown emails and for already-verified accounts (which get no email). Throttled to 3 resends per rolling 24 hours per account.","operationId":"resendVerification","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Generic acknowledgement — sent regardless of account existence or verification state (anti-enumeration)","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Too many resend requests for this account (max 3 per 24 hours)","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.resend-verification","description":"Request a fresh email-verification code"}],"x-since":"8.16.5"}},"/v4/users/register":{"post":{"tags":["Users"],"summary":"Register a new user","description":"**Since v7.0.0** — Creates a new user account backed by Keycloak. A verification email is sent, except when the invitation code is an emailed approval code (request-to-join, #1005) and the registering email matches the approved request: mailbox ownership is already proven by delivery of the approval email, so the account is created verified (response field `validated: true`) and no verification email is sent.","operationId":"register","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreateRequest"}}},"required":true},"responses":{"201":{"description":"User registered. `validated: true` when the email-bound approval code skipped verification; otherwise a verification code was emailed.","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Email already registered. A Keycloak account with no matching app user is an orphan and is reclaimed automatically (deleted and recreated, #1066), so this 409 means a real app account exists — or the orphan was too privileged / still linked to reclaim.","content":{"*/*":{"schema":{"type":"object"}}}},"503":{"description":"Registration temporarily unavailable — `{ error, message }` where `error` is `auth_unavailable` (the authentication service did not answer its availability probe), `auth_error` (it answered but rejected the create), or `mail_unavailable` (the account was created but the verification email could not be sent, so the registration was rolled back).","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.create","description":"Register a new user account"}],"x-since":"7.0.0"}},"/v4/users/me/messages/{id}/read":{"post":{"tags":["Notifications"],"summary":"Mark a message read","description":"**Since v9.82.0** — Stamps read_at on one of the caller's messages; it then leaves the unread set and the notifications feed. Idempotent: a message already read keeps its original timestamp. A message that is not the caller's is a 404.","operationId":"markRead","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The updated UserMessageResponse","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not one of the caller's messages","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.message.read","description":"Mark one of the caller's messages read"}],"x-since":"9.82.0"}},"/v4/users/me/integrations/{key}/test":{"post":{"tags":["Publishing"],"summary":"Test integration credentials","description":"**Since v7.6.0** — Tests the stored credentials for the specified integration. Always returns 200; check 'success' field.","operationId":"testCredentials","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test GitHub integration credentials"},{"name":"integration.zeenea.test","description":"Test Zeenea integration credentials"},{"name":"integration.kafka.test","description":"Test Control Center integration credentials"}],"x-since":"7.6.0"}},"/v4/users/me/integrations/{key}/test/field/{fieldName}":{"post":{"tags":["Publishing"],"summary":"Test a single integration field","description":"**Since v7.6.0** — Tests a specific field value without saving. Returns success/message/warning. Uses context or stored credentials for fields that require companion values.","operationId":"testField","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"fieldName","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Test result (check 'success' field)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration or field name","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test a single GitHub integration field"},{"name":"integration.zeenea.test","description":"Test a single Zeenea integration field"},{"name":"integration.kafka.test","description":"Test a single Control Center integration field"}],"x-since":"7.6.0"}},"/v4/users/me/api-key/rotate":{"post":{"tags":["Users"],"summary":"Rotate your own API key","description":"**Since v9.49.0** — Replaces the caller's API key and returns the new value **exactly once**. The previous key stops working immediately, including on requests that would otherwise have been served from the auth cache.","operationId":"rotateOwnApiKey","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Key rotated; the new key is shown once","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Not authenticated","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.apikey.rotate","description":"Rotate your own API key"}],"x-since":"9.49.0"}},"/v4/signing/keys":{"get":{"tags":["Signing"],"summary":"Get signing certificate metadata","description":"**Since v4.4.32** — Returns certificate metadata (fingerprint, subject, expiry). Never returns the private key.","operationId":"getKeys","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Certificate metadata","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No signing credentials configured","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signing-key.get","description":"Get signing certificate metadata"}],"x-since":"4.4.32"},"post":{"tags":["Signing"],"summary":"Upload signing key pair","description":"**Since v4.4.32** — Uploads a PKCS#8 PEM private key and X.509 PEM certificate chain. The private key is encrypted at rest (AES-256-GCM). Replaces any existing credentials. The certificate field accepts a concatenated PEM chain (leaf + intermediates).","operationId":"uploadKeys","parameters":[{"name":"privateKey","in":"query","required":true,"schema":{"type":"string"}},{"name":"certificate","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Credentials stored","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid key or certificate format","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signing-key.upload","description":"Upload a signing key pair"}],"x-since":"4.4.32"},"delete":{"tags":["Signing"],"summary":"Delete signing credentials","description":"**Since v4.4.32** — Removes the signing key pair and certificate. This cannot be undone.","operationId":"deleteKeys","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Credentials deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signing-key.delete","description":"Delete signing credentials"}],"x-since":"4.4.32"}},"/v4/signing/keys/test":{"post":{"tags":["Signing"],"summary":"Test a signing key pair (pre-flight, no persistence)","description":"**Since v7.39.0** — Verifies that a PKCS#8 PEM private key cryptographically matches an X.509 PEM certificate's public key, without storing anything. Returns the match verdict, the detected algorithm, and the leaf certificate's validity window. A malformed PEM or a mismatch is returned with matches=false and an error message (HTTP 200), not a 4xx/5xx.","operationId":"testKeys","parameters":[{"name":"privateKey","in":"query","required":true,"schema":{"type":"string"}},{"name":"certificate","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Test result (matches true/false)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signing-key.test","description":"Test a signing key pair without storing it"}],"x-since":"7.39.0"}},"/v4/signing/keys/generate":{"post":{"tags":["Signing"],"summary":"Generate signing key pair","description":"**Since v4.4.32** — Generates a new RSA-2048 or ECDSA P-256 key pair with a self-signed X.509 certificate (1 year validity). Returns the private key PEM as a ONE-TIME DOWNLOAD — it cannot be retrieved again. The encrypted key and certificate are stored for signing operations. Costs 50 Credits.","operationId":"generateKeys","parameters":[{"name":"algorithm","in":"query","required":false,"schema":{"type":"string","default":"RSA"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Key pair generated — private key in response body","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid algorithm (use RSA or ECDSA)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signing-key.mint","description":"Generate a signing key pair"}],"x-since":"4.4.32"}},"/v4/self-report":{"post":{"tags":["Self-Report"],"summary":"Submit an in-app help/feedback report","description":"**Since v7.0.55** — Creates a GitHub issue from the report. Error responses carry a JSON `{message, reason}` body where `reason` is a stable machine-readable code the client maps to user copy (#753/#757):\n- `invalid_request` (400) — local validation failed (blank/oversize/bad-type).\n- `rate_limited` (429) — caller exceeded the per-IP/per-email hourly cap.\n- `github_unreachable` (502) — GitHub was unreachable (network/5xx/429) after bounded retries; the report is persisted server-side for recovery.\n- `github_rejected` (502) — GitHub was reachable but rejected the request (non-auth 4xx, e.g. 404/422); the report is persisted server-side for recovery.\n- `github_auth` (503) — the server's GitHub token was rejected (misconfigured).\n- `not_configured` (503) — self-report is not configured on this server.\nNote: a payload larger than the gateway body cap is rejected upstream by nginx with a 413 before it reaches this endpoint.","operationId":"submit","parameters":[{"name":"description","in":"query","required":true,"schema":{"type":"string"}},{"name":"context","in":"query","required":false,"schema":{"type":"string"}},{"name":"attachment","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","format":"binary"}}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Report accepted; issue created.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed — reason `invalid_request`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate-limited — reason `rate_limited`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"502":{"description":"GitHub-origin failure — reason `github_unreachable` or `github_rejected`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"503":{"description":"Server-side GitHub config error — reason `github_auth` or `not_configured`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"x-intent":[{"name":"self-report.create","description":"Submit an in-app help/feedback report"}],"x-since":"7.0.55"}},"/v4/reference-tags":{"get":{"tags":["Tags"],"summary":"List all reference tags (v4, born-deprecated)","description":"**Since v7.1.3** — Returns all reference tags created by the authenticated user. Verbatim copy of /v1/reference-tags.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listTags","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.list","description":"List all reference tags"}],"x-since":"7.1.3","x-sunset":"2027-01-01"},"post":{"tags":["Tags"],"summary":"Create a reference tag (v4, born-deprecated)","description":"**Since v7.1.3** — Creates a new reference tag with the specified properties. Verbatim copy of POST /v1/reference-tags.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"createTag","parameters":[{"name":"tagName","in":"query","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.create","description":"Create a reference tag"}],"x-since":"7.1.3","x-sunset":"2027-01-01"}},"/v4/products":{"get":{"tags":["Products"],"summary":"List product headers","description":"**Since v7.13.3** — Returns header fields for all products. Pass org or orgId to list organization products.","operationId":"readHeaders","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of product header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.list","description":"List data product headers"}],"x-since":"7.13.3"},"post":{"tags":["Products"],"summary":"Upload a data product","description":"**Since v7.13.3** — Uploads an ODPS YAML data product file directly. Pass org or orgId to upload to an organization's storage.\n\n**apiVersion (#1073)**: an uploaded document carries its own `apiVersion` and **the file always wins** — this parameter cannot change what is stored here. It is still validated, so an unsupported value is a 400 rather than being silently dropped. To choose a standard version for a *generated* product, use `POST /v4/products` with `contractId`.","operationId":"create","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractVersion","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"apiVersion","in":"query","description":"*(since 8.32.0)* Which edition of the standard a newly *generated* artifact declares, e.g. `v3.2.0` (the leading `v` is optional). Omit it to get the current production version, which is what this endpoint has always emitted. **ODCS v3.2.0 is still a draft here and is subject to change** — see `GET /v4/artifacts/supported-versions` for each version's status. Ignored when you upload a document that already declares its own `apiVersion`: the file wins. An unsupported or cross-standard value is a 400.","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Product uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload error","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid file type","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.upload","description":"Upload an ODPS YAML data product file"}],"x-since":"7.13.3"},"delete":{"tags":["Products"],"summary":"Delete a data product","description":"**Since v7.13.3** — Soft-deletes a specific product version. Pass org or orgId for organization products.","operationId":"delete_2","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product version"}],"x-since":"7.13.3"}},"/v4/products/{productId}/upgrade":{"post":{"tags":["Products"],"summary":"Upgrade a product's declared apiVersion","description":"**Since v9.33.0** — Rewrites the ODPS edition a stored product declares — for example moving a `v1.0.0` product to `v1.1.0` (#1092).\n\n**This is not the artifact's own version.** `apiVersion` is the edition of the *standard* the document is written against; `version` is the product's own semver. Upgrading one never changes the other, in either direction.\n\n**Never automatic.** No background migration, no upgrade-on-save, and changing a workspace's standard-version channel (#1091) does not touch a stored file.\n\n**By default, either it succeeds or nothing is written.** The rewritten document is validated against the target schema first; if it would not pass, the stored file is untouched. **Pass `force=true` to override that one refusal** (#1205): the document is written anyway and the response carries `forced: true`, the overridden validation errors and a warning — the artifact then declares an edition its content does not satisfy. `force` does not override a lossy downgrade, and with `dryRun=true` it still writes nothing.\n\n**A lossy downgrade is refused**, with the offending fields named rather than deleted. **A signature is cleared, visibly**, because it covered the previous bytes.\n\nUpgrading to the version the artifact already declares is a no-op success. Single artifact only.","operationId":"upgradeProductApiVersion","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"The product's own semver, to pick which stored version to change","required":false,"schema":{"type":"string"}},{"name":"apiVersion","in":"query","description":"Target ODPS edition, e.g. v1.1.0","required":true,"schema":{"type":"string"}},{"name":"dryRun","in":"query","description":"Report what would change without writing anything","required":false,"schema":{"type":"boolean","default":false}},{"name":"force","in":"query","description":"#1205 — write anyway when the ONLY objection is that the rewritten document fails target-schema validation. Does not override a lossy downgrade, an unsupported target, an unreadable document, or a missing/duplicated apiVersion. A forced write still clears a signature, and the response says plainly that the artifact now declares an edition its content does not satisfy.","required":false,"schema":{"type":"boolean","default":false}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Upgraded, or a dry-run report, or a no-op when already on the target","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported target version, a lossy downgrade, or a result that does not validate — nothing was written. A body carrying `forceable: true` says the refusal could be overridden with force=true","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.upgrade-api-version","description":"Move a stored product to a newer edition of the ODPS standard"}],"x-since":"9.33.0"}},"/v4/products/{productId}/sign":{"post":{"tags":["Products"],"summary":"Sign a data product","description":"**Since v4.4.32** — Digitally signs the specified product using the caller's signing key (or the workspace key when org is specified). The signature is embedded in customProperties as an enveloped signature using JCS (RFC 8785) canonicalization.","operationId":"signProduct","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Product signed successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or signing credentials not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Signing failed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.sign","description":"Digitally sign a data product"}],"x-since":"4.4.32"},"delete":{"tags":["Products"],"summary":"Unsign a data product","description":"**Since v7.43.52** — Removes the enveloped signature from the specified product and records the per-artifact auto-sign opt-out (customProperties autosign=false) so no automatic path re-signs it. A subsequent manual sign clears the opt-out.","operationId":"unsignProduct","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Signature removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found, or product has no signature","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Unsign failed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.unsign","description":"Remove the digital signature from a data product"}],"x-since":"7.43.52"}},"/v4/products/{productId}/attachments":{"get":{"tags":["V4 - Product attachments"],"summary":"List a data product's attachments","description":"**Since v9.99.0** — Returns the entries from the product's `customProperties[property=attachments].value[]`, sorted by `url`.\n\n**Read from the document, not from a directory scan.** The persisted document is what publishes, so a file on disk with no entry is deliberately invisible here. External entries — an absolute `http(s)` url with no `#` — are returned like any other and are never read from disk.","operationId":"list","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The attachment entries, sorted by url","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not permitted for this product","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"product.attachment.list","description":"List a data product's attachments"}],"x-since":"9.99.0"},"post":{"tags":["V4 - Product attachments"],"summary":"Attach a file to a draft data product","description":"**Since v9.99.0** — Uploads one file and appends an entry to the product's `customProperties[property=attachments].value[]`.\n\n**`customProperties` is the source of truth for the list; the filesystem is the source of truth for the bytes.** An entry carries `name`, `mimeType`, `size`, `url`, `role` and `sha256`. A `#` prefix on `url` marks an internal (attached) file; an absolute `http(s)` url marks an external link that is never materialised.\n\n`size` and `sha256` are computed from the received bytes and are never taken from the caller — a client-supplied digest describes what the client meant to send.\n\n**Draft products only.** Attaching to a published product would change what was published without a version, so it is refused with a message naming the reason.\n\nUploading two files with the same name is resolved deterministically: the second is stored as `name-2.ext` rather than overwriting the first or producing an entry that cannot be told apart from it. Re-uploading **identical content** under the same name is a no-op on the bytes, because a second copy of a file you already attached helps nobody.","operationId":"upload","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"role","in":"query","description":"doc | sbom | sample | license | other. Defaults to other.","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"Attached; the created entry is returned","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid filename, role, or a product that is not a draft","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not permitted for this product","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"product.attachment.upload","description":"Attach a file to a data product"}],"x-since":"9.99.0"}},"/v4/products/publish-github":{"post":{"tags":["Products"],"summary":"Publish product to GitHub","description":"**Since v7.26.0** — Enhanced publish with pre-publish version check, Git tagging, and auto-publish of referenced contracts. Compares local content against the last published version (via scoped Git tags). Returns SKIP if identical, CONFLICT (409) if version not bumped, or publishes and tags on success. Referenced contracts from outputPorts/inputPorts are automatically checked and published. Pass org or orgId to publish from an organization's storage using the org's GitHub token.","operationId":"publishToGitHub","parameters":[{"name":"productId","in":"query","description":"UUID of the data product to publish","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Semantic version of the product to publish (e.g. 1.2.3). Defaults to the product's current version when omitted.","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"GitHub branch to publish to. Defaults to the branch encoded in the product's canonicalUrl, falling back to the repo's default branch.","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","description":"Force publish — skip pre-publish version conflict check","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Product published (or skipped if identical). Includes tag, skipped flag, and per-contract results","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token, missing canonicalUrl, or invalid GitHub URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Version conflict — product or referenced contract version not bumped. Returns per-contract details when contracts conflict","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.publish","description":"Publish a data product to GitHub"}],"x-since":"7.26.0"}},"/v4/podemites/grant":{"post":{"tags":["Podemites"],"summary":"Grant bonus Podemites (admin)","description":"**Since v9.53.0** — Grants Podemites to a user by email, with **no** credit consumption behind them. The comment is mandatory: a bonus is the one kind of award with no transaction to explain it, so the comment is the only record of why the Podemites exist. The award is written with source=BONUS, distinguishable in the ledger from a consumption-derived one.","operationId":"grantBonus","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"comment","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Bonus granted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Non-positive amount, or a missing comment","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Target user not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"podemite.grant","description":"Grant bonus Podemites to a user (admin)"}],"x-since":"9.53.0"}},"/v4/pdf-settings":{"get":{"tags":["Publishing"],"summary":"Read PDF settings (v4)","description":"**Since v8.10.0** — Returns the page size and footer this workspace renders its branded PDFs with (#977). `footer` is the footer the workspace explicitly set, or null when it has never set one — a client should render null as an empty field meaning \"use the automatic workspace copyright\". `effectiveFooter` is what actually prints today.","operationId":"getPdfSettings","responses":{"200":{"description":"The saved report format","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PdfSettingsResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"pdf-settings.read","description":"Read the saved PDF rendering settings"}],"x-since":"8.10.0"},"post":{"tags":["Publishing"],"summary":"Update PDF settings (v4)","description":"**Since v7.4.0** — Updates PDF rendering settings (page size and footer message).","operationId":"updatePdfSettings","parameters":[{"name":"size","in":"query","required":true,"schema":{"type":"string"}},{"name":"footer","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"PDF settings updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to update settings file","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"pdf-settings.update","description":"Update PDF rendering settings"}],"x-since":"7.4.0"}},"/v4/orgs/{slug}/settings/pdf-settings":{"post":{"tags":["Organization Settings"],"summary":"Update organization PDF settings (deprecated slug path)","description":"**Since v7.5.0** — Updates PDF rendering settings (page size, footer) for the organization. Requires ADMIN+ role. Deprecated — use POST /v4/orgs/settings/pdf-settings with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updatePdfSettingsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"size","in":"query","required":true,"schema":{"type":"string"}},{"name":"footer","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"PDF settings updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to update settings","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.5.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/settings/logo":{"get":{"tags":["Organization Settings"],"summary":"Get organization logo (deprecated slug path)","description":"**Since v7.5.0** — Returns the organization's current SVG logo. Requires org membership. Deprecated — use GET /v4/orgs/settings/logo with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getLogoBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SVG logo content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found or no logo","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.5.0","x-sunset":"2027-01-01"},"post":{"tags":["Organization Settings"],"summary":"Upload organization logo (deprecated slug path)","description":"**Since v7.5.0** — Uploads an SVG logo for the organization's PDF contract renderings. Requires ADMIN+ role. Deprecated — use POST /v4/orgs/settings/logo with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"uploadLogoBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Uploaded file is not a valid SVG","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Logo already exists (use force=true)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File I/O error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.5.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/products":{"get":{"tags":["Organization Products"],"summary":"List organization product headers","description":"**Since v7.9.0** — Returns header fields for all products in the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of product headers","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.list","description":"List data product headers"}],"x-since":"7.9.0","x-sunset":"2027-01-01"},"post":{"tags":["Organization Products"],"summary":"Upload a product to the organization","description":"**Since v7.9.0** — Uploads an ODPS YAML file directly to the organization's storage.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractVersion","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"apiVersion","in":"query","description":"*(since 8.32.0)* Which edition of the standard a newly *generated* artifact declares, e.g. `v3.2.0` (the leading `v` is optional). Omit it to get the current production version, which is what this endpoint has always emitted. **ODCS v3.2.0 is still a draft here and is subject to change** — see `GET /v4/artifacts/supported-versions` for each version's status. Ignored when you upload a document that already declares its own `apiVersion`: the file wins. An unsupported or cross-standard value is a 400.","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Product uploaded","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Product creation error","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid file type","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.upload","description":"Upload an ODPS YAML data product file"}],"x-since":"7.9.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Products"],"summary":"Delete an organization product","description":"**Since v7.9.0** — Soft-deletes a specific product version from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product deleted","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product version"}],"x-since":"7.9.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/products/publish-github":{"post":{"tags":["Organization Products"],"summary":"Publish organization product to GitHub","description":"**Since v7.9.0** — Pushes the product YAML to GitHub.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Product published","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token or canonicalUrl","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.publish","description":"Publish a data product to GitHub"}],"x-since":"7.9.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/messages/{messageId}/resend":{"post":{"tags":["Membership"],"summary":"Resend a pending invitation (deprecated slug path)","description":"**Since v7.43.15** — Owner/admin re-sends the invitation email for a PENDING invitation. Deprecated — use POST /v4/orgs/messages/{messageId}/resend with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"resendInvitationBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Invitation email re-sent","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found, not pending, or not an invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.43.15","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/join":{"post":{"tags":["Membership"],"summary":"Request to join an organization (deprecated slug path)","description":"**Since v7.11.0** — Submits a join request that must be approved by an org admin or owner. Deprecated — use POST /v4/orgs/join with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"joinRequestBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"message","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Join request created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Already a member or pending request exists","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/invite":{"post":{"tags":["Membership"],"summary":"Invite a user to the organization (deprecated slug path)","description":"**Since v7.11.0** — Admin/owner invites a user by email. The user must accept the invitation. Deprecated — use POST /v4/orgs/invite with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"inviteBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"message","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Invitation created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Already a member or pending invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/integrations/{key}/test":{"post":{"tags":["Organization Settings"],"summary":"Test org integration credentials (deprecated slug path)","description":"**Since v7.10.0** — Tests the stored credentials of an org integration. Requires ADMIN+ role. Deprecated — use POST /v4/orgs/integrations/{key}/test with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testCredentialsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/integrations/{key}/test/field/{fieldName}":{"post":{"tags":["Organization Settings"],"summary":"Test a single org integration field (deprecated slug path)","description":"**Since v7.10.0** — Tests a specific field value without saving. Returns success/message/warning. Uses context or stored credentials for fields that require companion values. Deprecated — use POST /v4/orgs/integrations/{key}/test/field/{fieldName} with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testFieldBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"fieldName","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Test result (check 'success' field)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration or field name","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/domains":{"post":{"tags":["Organizations"],"summary":"Add domain to organization (deprecated slug path)","description":"**Since v7.7.0** — Adds an email domain to the organization for discovery. Requires ADMIN+ role. Deprecated — use POST /v4/orgs/domains with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"addDomainBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"domain","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Domain added","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain blocked or already claimed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organizations"],"summary":"Remove domain from organization (deprecated slug path)","description":"**Since v7.7.0** — Removes an email domain from the organization. Requires ADMIN+ role. Deprecated — use DELETE /v4/orgs/domains with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeDomainBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"domain","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain not found or doesn't belong to this org","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.7.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/credits/transfer":{"post":{"tags":["Credits"],"summary":"Transfer Credits from org to user","description":"**Since v7.44.0** — Transfers Credits from the organization's balance to a user's personal balance. Requires ADMIN or OWNER role in the organization.","operationId":"transferOrgCreditsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Credits transferred","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid amount or insufficient org balance","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not an admin/owner of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or target user not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.org.transfer","description":"Transfer Credits from org to user"}],"x-since":"7.44.0"}},"/v4/orgs/{slug}/credits/grant":{"post":{"tags":["Credits"],"summary":"Grant Credits to an organization (admin)","description":"**Since v7.44.0** — Admin grants Credits to an organization by slug.","operationId":"grantOrgCreditsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"comment","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Credits granted to organization","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.org.grant","description":"Grant Credits to an organization (admin)"}],"x-since":"7.44.0"}},"/v4/orgs/{slug}/contracts":{"get":{"tags":["Organization Contracts"],"summary":"List organization contract headers","description":"**Since v7.8.0** — Returns header fields for all contracts in the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_2","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"JSON array of contract headers","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.list","description":"List organization contract headers"}],"x-since":"7.8.0","x-sunset":"2027-01-01"},"post":{"tags":["Organization Contracts"],"summary":"Upload a contract to the organization","description":"**Since v7.8.0** — Uploads an ODCS YAML or DDL file to the organization's storage. Requires org membership.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_2","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sourceFormat","in":"query","required":false,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"apiVersion","in":"query","description":"*(since 8.32.0)* Which edition of the standard a newly *generated* artifact declares, e.g. `v3.2.0` (the leading `v` is optional). Omit it to get the current production version, which is what this endpoint has always emitted. **ODCS v3.2.0 is still a draft here and is subject to change** — see `GET /v4/artifacts/supported-versions` for each version's status. Ignored when you upload a document that already declares its own `apiVersion`: the file wins. An unsupported or cross-standard value is a 400.","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"ddlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"dbmlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"odcsUrl","in":"query","description":"#1180 — with sourceFormat=odcs (or auto), fetch the ODCS document from this URL server-side instead of uploading it. Imported verbatim; same guards as ddlUrl/dbmlUrl.","required":false,"schema":{"type":"string"}},{"name":"includeViews","in":"query","description":"When sourceFormat=jdbc, also introspect database views (#185 TD-5). Views are added as SchemaObjects tagged 'view'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"includeRoutines","in":"query","description":"When sourceFormat=jdbc, also discover stored procedures and functions (#186 TD-6). Attached as JSON customProperties 'storedProcedures' and 'storedFunctions'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"jdbcConnection":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}}}}},"responses":{"200":{"description":"Contract uploaded","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.create","description":"Upload a contract to the organization"}],"x-since":"7.8.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Contracts"],"summary":"Delete an organization contract","description":"**Since v7.8.0** — Soft-deletes a specific contract version from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_4","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Contract deleted","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete an organization contract"}],"x-since":"7.8.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/contracts/transfer":{"post":{"tags":["Organization Contracts"],"summary":"Transfer artifacts from personal to org storage","description":"**Since v7.8.0** — Moves contracts and/or products from the authenticated user's personal storage into the organization. Transfer is all-or-nothing: if any item fails validation, nothing is transferred. The request body is a JSON array of TransferItem objects.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"transferArtifacts","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TransferItem"}}}},"required":true},"responses":{"200":{"description":"Artifacts transferred successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Validation failed (missing artifacts, invalid types)","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File transfer error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.transfer","description":"Transfer artifacts to org storage"}],"x-since":"7.8.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/contracts/publish-github":{"post":{"tags":["Organization Contracts"],"summary":"Publish organization contract to GitHub","description":"**Since v7.8.0** — Pushes the contract YAML to GitHub. Uses the organization's GitHub token if configured.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_2","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Contract published","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token or canonicalUrl","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.publish","description":"Publish organization contract to GitHub"}],"x-since":"7.8.0","x-sunset":"2027-01-01"}},"/v4/orgs/settings/pdf-settings":{"get":{"tags":["Organization Settings"],"summary":"Read organization PDF settings","description":"**Since v8.10.0** — Returns the page size and footer the organization renders its branded PDFs with (#977). Pass org (slug) or orgId (UUID) to select the organization. Readable by any MEMBER, like the logo. `footer` is null when the organization has never set one; `effectiveFooter` is what actually prints.","operationId":"getPdfSettings_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The saved report format","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PdfSettingsResponse"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.pdf.read","description":"Read the organization's PDF rendering settings"}],"x-since":"8.10.0"},"post":{"tags":["Organization Settings"],"summary":"Update organization PDF settings","description":"**Since v7.26.0** — Updates PDF rendering settings (page size, footer) for the organization. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"updatePdfSettings_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"size","in":"query","required":true,"schema":{"type":"string"}},{"name":"footer","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"PDF settings updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to update settings","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.pdf.update","description":"Update organization PDF rendering settings"}],"x-since":"7.26.0"}},"/v4/orgs/settings/logo":{"get":{"tags":["Organization Settings"],"summary":"Get organization logo","description":"**Since v7.26.0** — Returns the organization's current SVG logo. Pass org (slug) or orgId (UUID) to select the organization. Requires org membership.","operationId":"getLogo","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"SVG logo content","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found or no logo","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.logo.get","description":"Get the organization logo"}],"x-since":"7.26.0"},"post":{"tags":["Organization Settings"],"summary":"Upload organization logo","description":"**Since v7.26.0** — Uploads an SVG logo for the organization's PDF contract renderings. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"uploadLogo","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or not a valid SVG","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Logo already exists (use force=true)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File I/O error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.logo.upload","description":"Upload the organization logo"}],"x-since":"7.26.0"}},"/v4/orgs/service-accounts":{"get":{"tags":["Service Accounts"],"summary":"List the org's service accounts (org-ADMIN only)","description":"**Since v7.34.0** — No secret material in the response.","operationId":"list_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of service accounts (no secrets)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an ADMIN of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"serviceaccount.list","description":"List org service accounts"}],"x-since":"7.34.0"},"post":{"tags":["Service Accounts"],"summary":"Create a service account (org-ADMIN only)","description":"**Since v7.34.0** — Creates an OAuth2 service account owned by the organization. The response carries the client_id and the plaintext client_secret EXACTLY ONCE — only the BCrypt hash is persisted; record the secret immediately. Scopes are limited to contracts:read and contracts:publish (v1). Tokens come from POST /oauth2/token with grant_type=client_credentials (1 hour, ES256, no refresh token).","operationId":"create_3","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequest"}}},"required":true},"responses":{"200":{"description":"Service account created; client_secret shown once","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing name or unsupported scope","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an ADMIN of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"serviceaccount.create","description":"Create an org service account"}],"x-since":"7.34.0"}},"/v4/orgs/service-accounts/{id}/rotate":{"post":{"tags":["Service Accounts"],"summary":"Rotate a service-account secret (org-ADMIN only)","description":"**Since v7.34.0** — Replaces the client_secret; the new plaintext is returned EXACTLY ONCE. The previous secret stops working immediately. A revoked account stays revoked.","operationId":"rotate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Secret rotated; new client_secret shown once","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an ADMIN of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or service account not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"serviceaccount.rotate","description":"Rotate a service-account secret"}],"x-since":"7.34.0"}},"/v4/orgs/plugins":{"get":{"tags":["Organization Plugins"],"summary":"List registered plugins","description":"**Since v9.2.0** — Lists the plugins registered for the organization with their last sync status. Pass org (slug) or orgId (UUID). Requires org membership.","operationId":"list_2","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of plugins","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.list","description":"List the organization's registered plugins"}],"x-since":"9.2.0"},"post":{"tags":["Organization Plugins"],"summary":"Register a plugin","description":"**Since v9.2.0** — Fetches and validates the manifest at the given URL and registers the plugin for the organization. The plugin contributes nothing until it is activated. Pass org (slug) or orgId (UUID). Requires ADMIN+ role.","operationId":"register_1","parameters":[{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginRegisterRequest"}}},"required":true},"responses":{"201":{"description":"Plugin registered","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Blocked URL, or an invalid manifest (with the reason)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"That plugin id is already registered for the organization","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.register","description":"Register a plugin by manifest URL"}],"x-since":"9.2.0"}},"/v4/orgs/plugins/{id}/sync":{"post":{"tags":["Organization Plugins"],"summary":"Re-sync a plugin","description":"**Since v9.2.0** — Re-fetches and re-validates the plugin's manifest; a version change is the change signal. A failed fetch is reported in lastError rather than failing the call. Requires ADMIN+ role.","operationId":"sync","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The plugin after re-sync","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or plugin not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.sync","description":"Re-fetch a plugin's manifest"}],"x-since":"9.2.0"}},"/v4/orgs/plugins/{id}/activate":{"post":{"tags":["Organization Plugins"],"summary":"Activate a plugin","description":"**Since v9.3.0** — Activates a registered plugin for the organization. Idempotent. The org admin who activates it owns the relationship and is responsible for what the plugin does with the data it receives — see GET /v4/orgs/plugins/{id}/disclosure. Requires ADMIN+ role.","operationId":"activate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The plugin after activation","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or plugin not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.activate","description":"Activate a plugin for the organization"}],"x-since":"9.3.0"},"delete":{"tags":["Organization Plugins"],"summary":"Deactivate a plugin","description":"**Since v9.3.0** — Deactivates the plugin for the organization. Idempotent. The registration and every member's saved settings are kept. Requires ADMIN+ role.","operationId":"deactivate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The plugin after deactivation","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or plugin not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.deactivate","description":"Deactivate a plugin for the organization"}],"x-since":"9.3.0"}},"/v4/orgs/plugins/invoke":{"post":{"tags":["Organization Plugins"],"summary":"Invoke a plugin","description":"**Since v9.6.0** — Proxies a JSON-RPC message/send to the plugin's endpoint, server-side and SSRF-guarded, so the browser never calls a third-party URL. The payload scope, the interaction mode and the endpoint all come from the stored manifest — never the request — so a client cannot ask for more than the org admin approved. The invoking member's name and email and their own saved settings are added server-side. Requires org membership.","operationId":"invoke","parameters":[{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginInvokeRequest"}}},"required":true},"responses":{"200":{"description":"{ reply, contextId, messageId, actions }","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId, a blocked endpoint, or a payload over 512 KB","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"The plugin action is not available here, or the artifact is not in this workspace","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"The plugin failed, timed out, or returned no reply","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.invoke","description":"Invoke a plugin contribution"}],"x-since":"9.6.0"}},"/v4/orgs/messages/{messageId}/resend":{"post":{"tags":["Membership"],"summary":"Resend a pending invitation","description":"**Since v7.43.15** — Owner/admin re-sends the invitation email for a PENDING invitation. Does NOT create a new message row. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"resendInvitation","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Invitation email re-sent","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId, message not found, not pending, or not an invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.invitation.resend","description":"Resend a pending organization invitation"}],"x-since":"7.43.15"}},"/v4/orgs/join":{"post":{"tags":["Membership"],"summary":"Request to join an organization","description":"**Since v7.26.0** — Submits a join request that must be approved by an org admin or owner. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"joinRequest","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"message","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Join request created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, already a member, or pending request exists","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.join","description":"Request to join an organization"}],"x-since":"7.26.0"}},"/v4/orgs/invite":{"post":{"tags":["Membership"],"summary":"Invite a user to the organization","description":"**Since v7.26.0** — Admin/owner invites a user by email. The user must accept the invitation. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"invite","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"message","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Invitation created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, already a member, or pending invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.invite","description":"Invite a user to the organization"}],"x-since":"7.26.0"}},"/v4/orgs/integrations/{key}/test":{"post":{"tags":["Organization Settings"],"summary":"Test org integration credentials","description":"**Since v7.26.0** — Tests the stored credentials of an org integration. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"testCredentials_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Test result (check 'success' field)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test org GitHub integration credentials"},{"name":"integration.zeenea.test","description":"Test org Zeenea integration credentials"},{"name":"integration.kafka.test","description":"Test org Control Center integration credentials"}],"x-since":"7.26.0"}},"/v4/orgs/integrations/{key}/test/field/{fieldName}":{"post":{"tags":["Organization Settings"],"summary":"Test a single org integration field","description":"**Since v7.26.0** — Tests a specific field value without saving. Returns success/message/warning. Uses context or stored credentials for fields that require companion values. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"testField_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"fieldName","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Test result (check 'success' field)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or unknown integration/field name","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test a single org GitHub integration field"},{"name":"integration.zeenea.test","description":"Test a single org Zeenea integration field"},{"name":"integration.kafka.test","description":"Test a single org Control Center integration field"}],"x-since":"7.26.0"}},"/v4/orgs/domains":{"post":{"tags":["Organizations"],"summary":"Add domain to organization","description":"**Since v7.26.0** — Adds an email domain to the organization for discovery. Requires ADMIN+ role. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"addDomain","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"domain","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"201":{"description":"Domain added","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, domain blocked, or already claimed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.domain.create","description":"Add an email domain to the organization"}],"x-since":"7.26.0"},"delete":{"tags":["Organizations"],"summary":"Remove domain from organization","description":"**Since v7.26.0** — Removes an email domain from the organization. Requires ADMIN+ role. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"removeDomain","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"domain","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter, domain not found, or doesn't belong to this org","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.domain.delete","description":"Remove an email domain from the organization"}],"x-since":"7.26.0"}},"/v4/orgs/agents/invoke":{"post":{"tags":["Organization Agent Providers"],"summary":"Invoke an agent","description":"**Since v8.9.0** — Proxies an A2A message/send to the chosen imported agent's endpoint. Invocation runs server-side (SSRF-guarded, redirects off) so the browser never calls third-party URLs. Pass org (slug) or orgId (UUID) and the agent's cardUrl (from GET /v4/orgs/agents). Requires org membership; the org must have agent support enabled.","operationId":"invoke_1","parameters":[{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentInvokeRequest"}}},"required":true},"responses":{"200":{"description":"The agent's reply","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId or message, or a blocked URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member, or agent support disabled","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or agent not imported","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"The agent failed, timed out, or returned no reply","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.agents.invoke","description":"Send a message to an imported agent via the A2A proxy"}],"x-since":"8.9.0"}},"/v4/orgs/agent-providers":{"get":{"tags":["Organization Agent Providers"],"summary":"List agent providers","description":"**Since v8.6.0** — Lists the A2A agent providers registered for the organization, each with its last sync status. Pass org (slug) or orgId (UUID). Requires org membership.","operationId":"list_3","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of agent providers","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.agents.providers.list","description":"List the organization's agent providers"}],"x-since":"8.6.0"},"post":{"tags":["Organization Agent Providers"],"summary":"Register an agent provider","description":"**Since v8.6.0** — Registers an A2A agent-registry URL for the organization and imports its agents. Pass org (slug) or orgId (UUID). Requires ADMIN+ role.","operationId":"add","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider registered","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId, or a malformed/blocked URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Provider URL already registered","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.agents.providers.add","description":"Register an agent provider"}],"x-since":"8.6.0"}},"/v4/orgs/agent-providers/{id}/sync":{"post":{"tags":["Organization Agent Providers"],"summary":"Re-sync an agent provider","description":"**Since v8.6.0** — Forces an immediate re-fetch of the provider's agents. Pass org (slug) or orgId (UUID). Requires ADMIN+ role. Sync failures are reported in the provider's lastError.","operationId":"sync_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Provider after re-sync","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or provider not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.agents.providers.sync","description":"Re-sync an agent provider"}],"x-since":"8.6.0"}},"/v4/onboarding/events":{"post":{"tags":["Onboarding"],"summary":"Record a visitor-side onboarding event","description":"**Since v8.16.7** — Public, anonymous beacon. Optional `e2e: true` marks the event as automated traffic, which `excludeTest` then drops from the onboarding funnel and journeys (#1281) — advisory and unauthenticated, since it can only hide the caller's own rows from an admin report. Accepts ONLY the visitor-side stages (landing_view, register_view, path_code, path_request) keyed by a client-generated visitorId — server-side stages are stamped by the backend at their authoritative transitions and are rejected here. No PII is accepted (email fields are ignored). Rate-limited per IP (60/hour).","operationId":"recordEvent","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"201":{"description":"Event recorded","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing visitorId, or a stage outside the visitor set","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Rate limit exceeded","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"onboarding.event.create","description":"Record a visitor-side onboarding funnel event"}],"x-since":"8.16.7"}},"/v4/maturity-history/capture":{"post":{"tags":["Maturity History"],"summary":"Trigger maturity snapshot capture (admin)","description":"**Since v7.2.0** — Admin-only. Immediately captures a maturity snapshot for today by scanning all contract and product files across all users and organizations. Requires Bearer JWT with admin privileges.","operationId":"captureSnapshot","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Snapshot captured","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.history.capture","description":"Trigger maturity snapshot capture"}],"x-since":"7.2.0"}},"/v4/logo":{"get":{"tags":["Publishing"],"summary":"Get logo (v4)","description":"**Since v7.4.0** — Returns the user's current SVG logo. User identified from JWT.","operationId":"getLogo_1","responses":{"200":{"description":"SVG logo content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No logo found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"logo.get","description":"Get the user's SVG logo"}],"x-since":"7.4.0"},"post":{"tags":["Publishing"],"summary":"Upload a logo (v4)","description":"**Since v7.4.0** — Uploads an SVG logo for PDF contract renderings. Use force=true to overwrite an existing logo.","operationId":"uploadLogo_1","parameters":[{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Uploaded file is not a valid SVG","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Logo already exists (use force=true to overwrite)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File I/O error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"logo.upload","description":"Upload an SVG logo"}],"x-since":"7.4.0"}},"/v4/interactions":{"post":{"tags":["Interactions"],"summary":"Record one pseudonymous Governance Coach interaction","description":"**Since v7.51.0** — Write-side telemetry for the Governance Coach (WB2 #893): the client posts the question, answer, RAG grounding, and maturity gaps under a client-generated random pseudonym. Requires a Bearer token. **The caller's identity is never stored or logged joinably with the record** — no user id, no email, no IP, no user-agent — and that half is permanent. Since #1483 the row may additionally carry `orgHash`, a peppered HMAC of the organization the question was asked in, resolved server-side and never read from this body; it is null for a personal workspace and while the feature is off. The interaction day is derived server-side at date precision (UTC); any client-supplied timestamp is ignored. Error responses carry the JSON `{message, reason}` body with reason `invalid_request` (400) when validation fails.","operationId":"record","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoachInteractionRequest"}}},"required":true},"responses":{"202":{"description":"Record accepted; empty body.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed — reason `invalid_request`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"x-intent":[{"name":"coach.interaction.record","description":"Record one pseudonymous Governance Coach interaction"}],"x-since":"7.51.0"}},"/v4/import":{"post":{"tags":["Import"],"summary":"Import a ZIP of ODCS/ODPS files","description":"**Since v7.50.0** — Unpacks the uploaded ZIP archive and creates every ODCS contract and ODPS product it contains (create-only: entries whose id+version already exist are skipped, never overwritten). Contracts are processed before products so products can reference contracts shipped in the same archive. Returns a per-file report; a partially failed import is a normal 200 outcome. Pass org or orgId to import into an organization's storage.","operationId":"importZip","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Per-file import report","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing, empty, or non-ZIP upload","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"artifact.import","description":"Bulk import ODCS/ODPS files from a ZIP archive"}],"x-since":"7.50.0"}},"/v4/github/workflow":{"post":{"tags":["Automation"],"summary":"Install GitHub Actions workflow (v4, born-deprecated)","description":"**Since v7.1.2** — Installs the upload-data-products workflow file in the specified repository. Org context, credit deduction, and integration-default resolution; v3-aligned (#640).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"installWorkflow","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Workflow installed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.workflow.install","description":"Install GitHub Actions workflow"}],"x-since":"7.1.2","x-sunset":"2027-01-01"}},"/v4/github/secrets":{"post":{"tags":["Automation"],"summary":"Set repository secrets (v4, born-deprecated)","description":"**Since v7.1.2** — Sets encrypted repository secrets for Zeenea integration. Org context, credit deduction; v3-aligned (#640).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setSecrets","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Secrets set","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token, invalid repo URL, or no secrets provided","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.secrets.update","description":"Set repository secrets"}],"x-since":"7.1.2","x-sunset":"2027-01-01"}},"/v4/github/provision-dispatcher-secrets":{"post":{"tags":["Automation"],"summary":"Provision dispatcher secrets (v4, born-deprecated)","description":"**Since v7.43.55** — Writes the dispatcher workflow's GitHub Actions secrets (ZEENEA_*, KAFKA_*, X_ORG_ID) to the product repo, sealed-box encrypted. Values come exclusively from server-side configuration (dispatcher.secrets.*) and the resolved org context — the request carries no secret material and cannot spoof another org's X_ORG_ID. Idempotent: re-running upserts (rotation = re-run). Requires an org context (#867).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"provisionDispatcherSecrets","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Secrets provisioned","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token, invalid repo URL, or no org context","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.secrets.provision-dispatcher","description":"Provision the dispatcher's GHA secrets from server-side configuration"}],"x-since":"7.43.55","x-sunset":"2027-01-01"}},"/v4/github/crawl-import":{"post":{"tags":["GitHub Crawl Import"],"summary":"Crawl a GitHub repo and import derived Teradata artifacts","description":"**Since v8.16.14** — Experimental, organization-gated. Crawls the requested folders of the given repository branch, detects Teradata SQL/BTEQ deterministically (no AI), derives one input contract per source table and one output contract per produced table (with ODCS transform* lineage and a mapped/unknown field inventory), assembles one ODPS product wiring the input and output ports, and uploads each source script under a deterministic content UUID (re-importing unchanged scripts is idempotent). Returns a per-artifact report.","operationId":"crawlImport","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlImportRequest"}}},"required":true},"responses":{"200":{"description":"Per-artifact import report","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing repoUrl or no crawlable files found","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not an org member, or the GitHub crawl-import feature is not enabled for this org","content":{"*/*":{"schema":{"type":"string"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github.crawl.import","description":"Crawl GitHub folders and derive Teradata contracts + a product (org-gated)"}],"x-since":"8.16.14"}},"/v4/github/crawl-import/stream":{"post":{"tags":["GitHub Crawl Import"],"summary":"Crawl a GitHub repo and import derived Teradata artifacts (streaming)","description":"**Since v8.18.0** — Server-Sent Events sibling of POST /v4/github/crawl-import (svc#1028). Same request body, org gating and auth. Emits `progress` events ({phase, message, done, total}) as each phase/artifact completes, then a terminal `done` event carrying the same ImportResultResponse as the non-streaming endpoint. On a runtime failure it emits an `error` event and completes. Sets `X-Accel-Buffering: no` so proxies do not buffer.","operationId":"crawlImportStream","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlImportRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of progress + a terminal done event","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"400":{"description":"Missing repoUrl","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"401":{"description":"Missing or invalid JWT","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"403":{"description":"Not an org member, or the feature is not enabled for this org","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"404":{"description":"Organization not found","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github.crawl.import.stream","description":"Streaming crawl+derive with live per-phase progress (org-gated)"}],"x-since":"8.18.0"}},"/v4/github/actions/trigger":{"post":{"tags":["Automation"],"summary":"Trigger workflow dispatch (v4, born-deprecated)","description":"**Since v7.1.2** — Triggers a workflow_dispatch event for the upload workflow. Org context, credit deduction, integration-default resolution; v3-aligned (#640).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"triggerWorkflow","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Workflow triggered","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.workflow.trigger","description":"Trigger a workflow dispatch"}],"x-since":"7.1.2","x-sunset":"2027-01-01"}},"/v4/diagnostics":{"get":{"tags":["Diagnostics"],"summary":"List diagnostics reports (admin only)","description":"**Since v7.1.1** — Paginated. Filters: type, email, since, until, resolved, appVersion, search, provenance, app.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"list_4","parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","required":false,"schema":{"type":"string"}},{"name":"until","in":"query","required":false,"schema":{"type":"string"}},{"name":"resolved","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"appVersion","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"provenance","in":"query","required":false,"schema":{"type":"string"}},{"name":"app","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Paginated list","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid Bearer JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"diagnostics.list","description":"List diagnostics reports"}],"x-since":"7.1.1","x-sunset":"2027-01-01"},"post":{"tags":["Diagnostics"],"summary":"Submit a diagnostics report","description":"**Since v7.1.1** — Unauthenticated. Accepts a single front-end error report.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"submit_1","parameters":[{"name":"X-CLI-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsReportRequest"}}},"required":true},"responses":{"201":{"description":"Report accepted","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Internal error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"x-intent":[{"name":"diagnostics.create","description":"Submit a front-end diagnostics report"}],"x-since":"7.1.1","x-sunset":"2027-01-01"}},"/v4/diagnostics/{id}/steps":{"get":{"tags":["Diagnostics"],"summary":"List a test-run's story steps (admin only)","description":"**Since v7.34.10** — Returns the ordered steps with descriptions, timestamps, payloads, and image URLs.","operationId":"listSteps","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Ordered steps","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid Bearer JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"diagnostics.step.list","description":"List a test-run's story steps"}],"x-since":"7.34.10"},"post":{"tags":["Diagnostics"],"summary":"Append a story step to a test-run","description":"**Since v7.34.10** — multipart/form-data: a `step` JSON part + an optional `screenshot` file part. Anonymous is allowed only for small text-only steps; any screenshot or an oversized step body requires a known caller (authenticated user or X-CLI-KEY).","operationId":"appendStep","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-CLI-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"step":{"type":"string"},"screenshot":{"type":"string","format":"binary"}},"required":["step"]}}}},"responses":{"201":{"description":"Step appended","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Malformed `step` JSON","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Anonymous caller attaching a file or oversized body","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Unknown or non-test-run parent","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"diagnostics.step.append","description":"Append a step (with optional screenshot) to a test-run"}],"x-since":"7.34.10"}},"/v4/demo/import":{"post":{"tags":["Demo"],"summary":"Import or refresh the demo set into your own workspace","description":"**Since v9.100.0** — Copies the Demo Customer 360 example from the **live demo organization** into the caller's personal workspace. The caller does not need to be a member of that organization — the read happens server-side on their behalf.\n\n**What happens to something you changed.** By default an artifact is written only when the service can *prove* your copy is untouched — pristine, deleted, or never received. Anything it cannot prove is untouched is **skipped** and listed in `skipped`. That includes artifacts you edited, and artifacts received before provenance was recorded, whose original bytes are unknowable. Pass `force=true` to overwrite those too.\n\n**Repeatable.** Calling this twice in a row writes the same set and creates no duplicates.\n\n**Never a partial import.** If the demo organization is missing, unreadable or empty, this fails with a message and writes nothing — an empty demo set is reported as an error, never as a successful import of zero artifacts.","operationId":"importDemoSet","parameters":[{"name":"force","in":"query","description":"Overwrite artifacts you have changed, or whose state cannot be determined. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"What was written and what was skipped","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ImportReport"}}}},"401":{"description":"Missing or invalid credentials","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"The feature is not enabled","content":{"*/*":{"schema":{"type":"object"}}}},"503":{"description":"The demo set is unavailable; nothing was written","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"demo.import","description":"Import or refresh the demo set"}],"x-since":"9.100.0"}},"/v4/data-sources/{name}/test":{"post":{"tags":["Data Sources"],"summary":"Test a named data source's connection","description":"**Since v7.35.0** — Opens a real JDBC connection using the stored coordinates and password. Returns ok=true on success, or ok=false with a message on an expected failure (bad credentials, unreachable host, unsupported vendor) — never a 5xx.","operationId":"test","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Connection test result (ok true/false)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such data source","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"datasource.test","description":"Test a named data source connection"}],"x-since":"7.35.0"}},"/v4/credits/redeem":{"post":{"tags":["Credits"],"summary":"Redeem a Credits code","description":"**Since v7.44.0** — Redeems a code to add Credits to the user's balance.","operationId":"redeemCode","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Code redeemed successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid or already-used code","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.code.redeem","description":"Redeem a code for Credits"}],"x-since":"7.44.0"}},"/v4/credits/grant":{"post":{"tags":["Credits"],"summary":"Grant Credits to a user (admin)","description":"**Since v7.44.0** — Admin grants Credits to a user by email.","operationId":"grantCredits","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"comment","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Credits granted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Target user not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.grant","description":"Grant Credits to a user (admin)"}],"x-since":"7.44.0"}},"/v4/credits/costs":{"get":{"tags":["Credits"],"summary":"List endpoint costs","description":"**Since v7.44.0** — Returns all configured Credits costs per endpoint.","operationId":"getCosts","responses":{"200":{"description":"Cost list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.cost.list","description":"List configured Credits endpoint costs"}],"x-since":"7.44.0"},"post":{"tags":["Credits"],"summary":"Create/update an endpoint cost (admin)","description":"**Since v7.44.0** — Admin sets the Credits cost for a specific API endpoint.","operationId":"saveCost","parameters":[{"name":"endpoint","in":"query","required":true,"schema":{"type":"string"}},{"name":"cost","in":"query","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"method","in":"query","required":false,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Cost saved","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.cost.update","description":"Create or update a Credits endpoint cost (admin)"}],"x-since":"7.44.0"},"delete":{"tags":["Credits"],"summary":"Delete an endpoint cost (admin)","description":"**Since v7.44.0** — Admin removes the Credits cost configuration for an endpoint.","operationId":"deleteCost","parameters":[{"name":"endpoint","in":"query","required":true,"schema":{"type":"string"}},{"name":"method","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cost deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Cost not found for endpoint","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.cost.delete","description":"Delete a Credits endpoint cost (admin)"}],"x-since":"7.44.0"}},"/v4/credits/codes":{"get":{"tags":["Credits"],"summary":"List all redeemable Credits codes (admin)","description":"**Since v7.44.0** — Admin view of all configured redemption codes.","operationId":"getAllCodes","responses":{"200":{"description":"Code list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.code.list","description":"List all redeemable Credits codes (admin)"}],"x-since":"7.44.0"},"post":{"tags":["Credits"],"summary":"Create a redeemable Credits code (admin)","description":"**Since v7.44.0** — Admin creates a redeemable code that users can apply to their balance.","operationId":"createCode","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"globalOnce","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"perUserOnce","in":"query","required":false,"schema":{"type":"boolean","default":true}},{"name":"comment","in":"query","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Code created","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.code.create","description":"Create a redeemable Credits code (admin)"}],"x-since":"7.44.0"}},"/v4/credits/bonuses":{"get":{"tags":["Credits"],"summary":"List all gamification bonus definitions (admin)","description":"**Since v7.44.0** — Returns all configured gamification bonus codes with their current amounts and enabled state. Admin only.","operationId":"listBonuses","responses":{"200":{"description":"Bonus list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.bonus.list","description":"List all gamification bonus definitions (admin)"}],"x-since":"7.44.0"},"post":{"tags":["Credits"],"summary":"Create a gamification bonus (admin)","description":"**Since v7.44.0** — Creates a new gamification bonus code with its description, user/org amounts, and enabled state. Admin only.","operationId":"createBonus","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Bonus created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing bonus code","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Bonus code already exists","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.bonus.create","description":"Create a gamification bonus (admin)"}],"x-since":"7.44.0"}},"/v4/contracts":{"get":{"tags":["Contracts"],"summary":"List contract headers","description":"**Since v7.13.4** — Returns header fields for all contracts. Pass org or orgId to list organization contracts.","operationId":"readHeaders_3","parameters":[{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of contract header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.list","description":"List contract headers"}],"x-since":"7.13.4"},"post":{"tags":["Contracts"],"summary":"Upload a data contract","description":"**Since v7.13.4** — Uploads an ODCS YAML file, a SQL DDL file, or creates a contract from a live JDBC database. Pass org or orgId to store in an organization's storage.\n\n**apiVersion (#1073)** selects which edition of ODCS a *generated* contract declares (the `ddl`, `dbml` and `jdbc` source formats). When you upload an ODCS document that already declares its own `apiVersion`, **the file wins and this parameter is ignored** — uploads carry their own version. Draft standards (v3.2.0) are subject to change before TSC approval.","operationId":"create_4","parameters":[{"name":"contractId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sourceFormat","in":"query","required":false,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"apiVersion","in":"query","description":"*(since 8.32.0)* Which edition of the standard a newly *generated* artifact declares, e.g. `v3.2.0` (the leading `v` is optional). Omit it to get the current production version, which is what this endpoint has always emitted. **ODCS v3.2.0 is still a draft here and is subject to change** — see `GET /v4/artifacts/supported-versions` for each version's status. Ignored when you upload a document that already declares its own `apiVersion`: the file wins. An unsupported or cross-standard value is a 400.","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"ddlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"dbmlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"odcsUrl","in":"query","description":"#1180 — with sourceFormat=odcs (or auto), fetch the ODCS document from this URL server-side instead of uploading it. Imported verbatim: id, name and version come from the document, so `name` is ignored on this path. Same guards as ddlUrl/dbmlUrl (http/https only, no redirects, 10s timeout, 500 KB cap, private addresses refused).","required":false,"schema":{"type":"string"}},{"name":"includeViews","in":"query","description":"When sourceFormat=jdbc, also introspect database views (#185 TD-5). Views are added as SchemaObjects tagged 'view'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"includeRoutines","in":"query","description":"When sourceFormat=jdbc, also discover stored procedures and functions (#186 TD-6). Attached as JSON customProperties 'storedProcedures' and 'storedFunctions'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"jdbcConnection":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}}}}},"responses":{"200":{"description":"Contract uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported source format or invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"422":{"description":"Invalid or malformed contract file (not YAML, unreadable, missing id/version, schema-invalid)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload or processing error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.create","description":"Upload a data contract"}],"x-since":"7.13.4"},"delete":{"tags":["Contracts"],"summary":"Delete a data contract","description":"**Since v7.13.4** — Soft-deletes a specific contract version. Pass org or orgId for organization contracts. A contract still referenced by data products is refused with 409 unless force=true, in which case it is first detached from every referencing product in the same storage context (input ports, output ports and outputPorts[].inputContracts entries are removed in place, at each product's current version, no new product version) and then deleted (#1397).","operationId":"delete_5","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"force","in":"query","description":"When true, detach the contract (any version of it) from every data product in the same storage context that references it, in place at each product's current version, then delete the contract. Detach and delete are one unit: a product that cannot be persisted aborts the call with 500 and nothing is changed. Default false, which keeps the 409 (#1397).","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Contract deleted. Plain-text message without force; with force=true the body is { deleted: { contractId, version }, detached: [ { productId, productVersion, name, portsRemoved } ] }","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ContractForceDeleteResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract is referenced by data products and force is not set; the body lists them as referencingProducts[] { productId, productName, productVersion }. Retry with force=true to detach the contract from them and delete it.","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"force=true and a referencing product could not be persisted; nothing was detached or deleted","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete a data contract"}],"x-since":"7.13.4"}},"/v4/contracts/{contractId}/upgrade":{"post":{"tags":["Contracts"],"summary":"Upgrade a contract's declared apiVersion","description":"**Since v9.33.0** — Rewrites the ODCS edition a stored contract declares — for example moving a `v3.1.0` contract to `v3.2.0` (#1092).\n\n**This is not the artifact's own version.** `apiVersion` is the edition of the *standard* the document is written against; `version` is the contract's own semver. Upgrading one never changes the other, in either direction. They are the two things most often confused, which is why the create endpoint uses a separate parameter name rather than overloading `version` (#1073).\n\n**Never automatic.** No background migration, no upgrade-on-save, and changing a workspace's standard-version channel (#1091) does not touch a stored file. An artifact moves only when someone calls this.\n\n**By default, either it succeeds or nothing is written.** The rewritten document is validated against the target schema first; if it would not pass, the operation fails and the stored file is untouched. **Pass `force=true` to override that one refusal** (#1205): the document is written anyway, the response carries `forced: true`, the validation errors it overrode, and a warning — the stored artifact then declares an edition its content does not satisfy, so validation, maturity assessment and GitHub publish will report it as invalid until those errors are fixed. `force` changes nothing else: with `dryRun=true` it still writes nothing.\n\n**A lossy downgrade is refused.** Moving back to an older edition would mean deleting fields that edition does not define. The response names them instead. Remove them deliberately first if that is genuinely what you want.\n\n**A signature is cleared, visibly.** A signature covers the document's bytes, so changing `apiVersion` breaks it. The response says so; the artifact is never left carrying a signature that no longer verifies, and it is never re-signed on your behalf.\n\nUpgrading to the version the artifact already declares is a no-op success.\n\nSingle artifact only — a workspace-wide migration is deliberately not this endpoint.","operationId":"upgradeContractApiVersion","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"The contract's own semver, to pick which stored version to change","required":false,"schema":{"type":"string"}},{"name":"apiVersion","in":"query","description":"Target ODCS edition, e.g. v3.2.0","required":true,"schema":{"type":"string"}},{"name":"dryRun","in":"query","description":"Report what would change without writing anything","required":false,"schema":{"type":"boolean","default":false}},{"name":"force","in":"query","description":"#1205 — write anyway when the ONLY objection is that the rewritten document fails target-schema validation. Does not override a lossy downgrade, an unsupported target, an unreadable document, or a missing/duplicated apiVersion. A forced write still clears a signature, and the response says plainly that the artifact now declares an edition its content does not satisfy.","required":false,"schema":{"type":"boolean","default":false}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Upgraded, or a dry-run report, or a no-op when already on the target","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported target version, a lossy downgrade, or a result that does not validate — nothing was written. A body carrying `forceable: true` says the refusal could be overridden with force=true","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.upgrade-api-version","description":"Move a stored contract to a newer edition of the ODCS standard"}],"x-since":"9.33.0"}},"/v4/contracts/{contractId}/test":{"post":{"tags":["Contracts"],"summary":"Run data-contract schema-conformance tests against a server","description":"**Since v7.36.0** — Synchronously connects to the named server declared in the contract, reads the live table metadata via JDBC, and compares it against the contract schema. Returns {status, server, checks[], log}. Connection credentials come from the stored per-server credential store (#718). Expected runtime failures (unknown server, missing credentials, unreachable host, unsupported vendor) return 200 with status:error, never a 5xx. Schema-conformance only; data-quality rule evaluation is deferred.","operationId":"testContract","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractTestRequest"}}},"required":true},"responses":{"200":{"description":"Test run result (status pass/fail/error)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing server name","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.test","description":"Run a contract's schema-conformance tests against a server"}],"x-since":"7.36.0"}},"/v4/contracts/{contractId}/sign":{"post":{"tags":["Contracts"],"summary":"Sign a data contract","description":"**Since v4.4.32** — Digitally signs the specified contract using the caller's signing key (or the workspace key when org is specified). The signature is embedded in customProperties as an enveloped signature using JCS (RFC 8785) canonicalization. Supports RS256 (RSA) and ES256 (ECDSA), auto-detected from the key type.","operationId":"signContract","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Contract signed successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or signing credentials not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Signing failed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.sign","description":"Digitally sign a data contract"}],"x-since":"4.4.32"},"delete":{"tags":["Contracts"],"summary":"Unsign a data contract","description":"**Since v7.43.52** — Removes the enveloped signature from the specified contract and records the per-artifact auto-sign opt-out (customProperties autosign=false) so no automatic path re-signs it. A subsequent manual sign clears the opt-out.","operationId":"unsignContract","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Signature removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found, or contract has no signature","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Unsign failed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.unsign","description":"Remove the digital signature from a data contract"}],"x-since":"7.43.52"}},"/v4/contracts/{contractId}/refresh":{"post":{"tags":["Contracts"],"summary":"Refresh a database-sourced contract (diff only, no write)","description":"**Since v7.33.0** — Re-introspects the contract's source database using the stored JDBC credentials and returns a diff against the live contract. No new contract version is written — drift is notify-only (activity entry + email to the caller). When version is omitted, the contract's latest version is used.","operationId":"refresh","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Diff report between the live contract and the fresh introspection","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract, organization, or stored credentials not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"Stored credentials invalid or introspection failed (diagnostics event recorded)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.refresh","description":"Refresh a database-sourced contract"}],"x-since":"7.33.0"}},"/v4/contracts/transfer":{"post":{"tags":["Contracts"],"summary":"Transfer artifacts from personal or org storage into an organization","description":"**Since v7.13.4** — Moves contracts and/or products into the destination organization. Requires org or orgId parameter. Default source is personal storage; pass fromOrg/fromOrgId to transfer org-to-org (#183) — the caller must hold the ADMIN role in BOTH organizations. Transfer is all-or-nothing.","operationId":"transferArtifacts_1","parameters":[{"name":"org","in":"query","description":"Destination organization slug (required)","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Destination organization UUID (required)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"fromOrg","in":"query","description":"Source organization slug (org-to-org transfer, #183)","required":false,"schema":{"type":"string"}},{"name":"fromOrgId","in":"query","description":"Source organization UUID (org-to-org transfer, #183)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TransferItem"}}}},"required":true},"responses":{"200":{"description":"Artifacts transferred successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Validation failed or no org specified","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File transfer error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.transfer","description":"Transfer artifacts to org storage"}],"x-since":"7.13.4"}},"/v4/contracts/test-connection":{"post":{"tags":["Contracts"],"summary":"Test JDBC database connection","description":"**Since v7.13.4** — Tests connectivity to a database without introspecting the schema.","operationId":"testConnection","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result (status: ok or error)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing required parameters","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.database.test","description":"Test JDBC database connection"}],"x-since":"7.13.4"}},"/v4/contracts/publish-github":{"post":{"tags":["Contracts"],"summary":"Publish contract to GitHub","description":"**Since v7.26.0** — Enhanced publish with pre-publish version check and Git tagging. Compares local content against the last published version (via scoped Git tags). Returns SKIP if identical, CONFLICT (409) if version not bumped, or publishes and tags on success. Pass org or orgId to publish from an organization's storage using the org's GitHub token.","operationId":"publishToGitHub_3","parameters":[{"name":"contractId","in":"query","description":"UUID of the data contract to publish","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Semantic version of the contract to publish (e.g. 1.2.3). Defaults to the contract's current version when omitted.","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"GitHub branch to publish to. Defaults to the branch encoded in the contract's canonicalUrl, falling back to the repo's default branch.","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","description":"Storage mode for the source file (\"permanent\" or \"draft\"). Defaults to permanent.","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"force","in":"query","description":"Force publish — skip pre-publish version conflict check","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Contract published (or skipped if identical). Includes tag and skipped flag","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token, missing canonicalUrl, or invalid GitHub URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Version conflict — content changed but version not bumped. Returns localVersion, githubVersion, suggestedVersion, and diffs","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.publish","description":"Publish contract to GitHub"}],"x-since":"7.26.0"}},"/v4/contact":{"post":{"tags":["Contact Sync"],"summary":"Sync a contact to MailerLite (v4, born-deprecated)","description":"**Since v7.1.4** — Accepts contact data and syncs to MailerLite. Verbatim behaviour of POST /v1/contact; v4 requires Bearer JWT (v1 used the legacy machine-identity filter).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"syncContact","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactSyncRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contact.transfer","description":"Sync a contact to MailerLite"}],"x-since":"7.1.4","x-sunset":"2027-01-01"}},"/v4/comments":{"get":{"tags":["Comments"],"summary":"List comments for an artifact","description":"**Since v5.0.0** — Returns all comments for the given artifact. Use the 'since' parameter for polling — returns only comments created, updated, or deleted after that time.","operationId":"listComments","parameters":[{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"artifactKind","in":"query","description":"Artifact kind: DataContract or DataProduct","required":true,"schema":{"type":"string"}},{"name":"artifactId","in":"query","description":"Artifact UUID","required":true,"schema":{"type":"string"}},{"name":"since","in":"query","description":"ISO 8601 timestamp for polling (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Comment list","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Not authenticated","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.list","description":"List comments for an artifact"}],"x-since":"5.0.0"},"post":{"tags":["Comments"],"summary":"Create a comment or reply","description":"**Since v5.0.0** — Creates a new comment anchored at artifact, section, or element level. Set parentId to reply to an existing comment (flat threading — no reply-to-reply).\n\n**`anchorType=PROFILE` is a message to a person, and carries extra rules** (#1453). An organization is **required** — pass `org` (slug) or `orgId`, or the request is rejected with 400. PROFILE comments are stored against an org and read back per org, so there is no org-less form of the thread; a personal workspace cannot send one.\n\nThe recipient is named by `targetHandle`, and must: have a **public profile**, be a **member of that same organization**, and not be you. A recipient who fails any of these is refused, and an unknown handle and a non-public profile are deliberately indistinguishable so this endpoint cannot be used to enumerate accounts.\n\nTo find out who can be messaged without guessing, read `GET /v4/orgs/members` and use the rows reporting `messageable: true` — that field is computed from the same predicate this endpoint enforces.","operationId":"createComment","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentRequest"}}},"required":true},"responses":{"201":{"description":"Comment created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request (e.g., reply-to-reply)","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.create","description":"Create a comment or reply"}],"x-since":"5.0.0"}},"/v4/comments/{id}/reactions":{"post":{"tags":["Comments"],"summary":"Add, replace or remove a reaction on a comment","description":"**Since v9.97.0** — Sets the calling user's reaction to a comment.\n\n**One reaction per user per comment, and the call toggles.** Sending the reaction you already left removes it; sending a different one replaces it. There is no multi-select, and the uniqueness is enforced by a database constraint rather than by a read-then-write, so a double-clicked button cannot create two rows.\n\nThe reaction set is a closed enum: `THUMBS_UP`, `THUMBS_DOWN`. Anything else is rejected with 400 rather than stored — a typo must not be recorded as the opposite of what the user clicked.\n\nCounts and the caller's own reaction come back on every comment read (`reactions`, `myReaction`), so rendering a thread needs no call per comment.","operationId":"react","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"reaction","in":"query","description":"THUMBS_UP or THUMBS_DOWN","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The caller's reaction after the call; `myReaction` is null when the call toggled it off","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unrecognised reaction","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the comment's organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such comment, or the feature is disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.react","description":"React to a comment"}],"x-since":"9.97.0"},"delete":{"tags":["Comments"],"summary":"Remove the caller's reaction from a comment","description":"**Since v9.97.0** — Removes the calling user's reaction, if any. **Idempotent** — removing a reaction that is not there is a success, not a 404, because a client retrying after a dropped response should not see an error for reaching the state it wanted.\n\nScoped to the caller's own reaction; there is no form of this call that removes somebody else's.","operationId":"removeReaction","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"The caller has no reaction on this comment","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the comment's organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such comment, or the feature is disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.unreact","description":"Remove your reaction from a comment"}],"x-since":"9.97.0"}},"/v4/catalogs/datasets/{datasetId}/import":{"post":{"tags":["External Catalogs"],"summary":"Import a dataset from an external catalog as a data contract","description":"**Since v7.2.0** — Fetches full dataset metadata from the catalog and generates an ODCS data contract. The contract is saved to disk and can be edited in the Workbench editor.","operationId":"importDataset","parameters":[{"name":"datasetId","in":"path","description":"Dataset ID in the external catalog","required":true,"schema":{"type":"string"}},{"name":"vendor","in":"query","description":"Catalog vendor (e.g., zeenea)","required":true,"schema":{"type":"string"}},{"name":"name","in":"query","description":"Override contract name","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Contract created successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown vendor","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Catalog credentials not configured","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract already exists for this dataset","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"Upstream catalog API error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"catalog.dataset.import","description":"Import a catalog dataset as a data contract"}],"x-since":"7.2.0"}},"/v4/badges/templates":{"get":{"tags":["Badges"],"summary":"List badge templates (admin)","description":"**Since v9.15.0** — Every template including disabled ones, in `sortOrder` — the admin view, unlike `GET /v4/badges`, which returns only what is enabled.","operationId":"list_5","responses":{"200":{"description":"All templates","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeTemplate"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeTemplate"}}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeTemplate"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.template.list","description":"List every badge template (admin)"}],"x-since":"9.15.0"},"post":{"tags":["Badges"],"summary":"Create a badge template (admin)","description":"**Since v9.15.0** — Adds a badge. Over a `criteriaSource` the evaluator already understands this needs no code change at all. `criteriaValue` is validated against `criteriaType` on write, and an unknown `criteriaSource` is rejected with the valid ones listed — an unrecognised source counts as zero, so accepting one would create a badge that can never be earned and gives no clue why.","operationId":"create_5","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadgeTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"That id already exists","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.template.create","description":"Create a badge template (admin)"}],"x-since":"9.15.0"}},"/v4/badges/refresh-credentials":{"post":{"tags":["Badges"],"summary":"Refresh stored badge credentials (admin)","description":"**Since v9.46.0** — Regenerates `credential_json` for existing awards, so a badge earned before a credential fix carries it.\n\n`credential_json` is written once, at award time, which means the OB 3.0 conformance work in 9.44.0 (#1237) reached **new awards only**. This is how an already-earned badge gets it.\n\n**A recomputation, not a repair.** The builder is deterministic and every input is already stored on the row — the award id, the template, the earner and when it was earned. Nothing is invented, and a second run changes nothing.\n\n**Only `credential_json` moves.** `awardedAt`, `evidence`, `periodStart` and `seenAt` are never touched, so this cannot alter what a badge means or when it was earned. No badge is awarded, revoked or re-dated. The credential's id is keyed on the award, so an already-imported badge updates rather than duplicating.\n\n**Scope is required.** Pass `email` for one user, or `all=true` for every award. A call with neither is a 400 — an unscoped default would be one typo away from rewriting every award on the instance.\n\nAn award whose template has left the catalog, or whose user no longer exists, is skipped and named in `skipped`; the rest of the pass still completes.","operationId":"refresh_1","parameters":[{"name":"email","in":"query","description":"Refresh only this user's awards","required":false,"schema":{"type":"string"}},{"name":"all","in":"query","description":"Refresh every award on the instance. Required when `email` is absent.","required":false,"schema":{"type":"boolean","default":false}},{"name":"dryRun","in":"query","description":"Report what would change and write nothing","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The pass completed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RefreshReport"}}}},"400":{"description":"No scope given — pass `email` or `all=true`","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No user holds that email","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.credential.refresh","description":"Regenerate the stored credential of existing badge awards (admin)"}],"x-since":"9.46.0"}},"/v4/artifacts/validate":{"post":{"tags":["Artifacts"],"summary":"Validate an ODCS contract or ODPS product against its JSON schema","description":"**Since v7.0.12** — Validates exactly the YAML posted in the body. The JSON Schema pass is stateless and returns one ValidationFinding per schema violation (severity = error). For kind=product, a second semantic pass runs when the YAML parses: it reads the caller's contract store to check ODPS port referential integrity — an input/output port contractId that resolves to no workspace contract yields a `warn`, and a contractId shared across output ports yields an `info` (semantic findings append to the schema findings, they never replace them). Malformed YAML is reported as a single parse-error finding, not a 5xx.\n\n`kind` accepts either vocabulary, case-insensitively: `contract` / `DataContract` and `product` / `DataProduct` (#1474), so the `kind` on a `GET /v4/artifacts` row can be handed straight back here. `App` is recognised vocabulary but has no schema to validate against, so it is rejected with 400.","operationId":"validateArtifact","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"[ValidationFinding] — empty array on a valid document","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing or invalid `kind` / `yaml` in the request body","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"artifact.validate","description":"Validate an artifact against its JSON schema"}],"x-since":"7.0.12"}},"/v4/artifacts/bundle":{"post":{"tags":["Artifacts"],"summary":"Apply an artifact bundle atomically","description":"**Since v8.19.0** — Creates every member of a bundle — typically a Data Product plus the contracts its output ports reference — as one all-or-nothing operation. Backs the assistant's `save_bundle` apply-bridge verb (svc#1006).\n\nContracts are always written before products, because a product whose `outputPorts[].contractId` does not yet resolve on disk is rejected. If any member fails, every artifact already written by this call is deleted and nothing is left persisted; the error names the failing member by its `role` or `suggestedName`.\n\nArtifacts live on disk rather than in rows, so atomicity here is compensating (write, then roll back on failure) rather than transactional. The observable guarantee is the same: either every member exists afterwards, or none does.\n\nRequest body: `{ \"members\": [ { \"content\": \"<full YAML>\", \"kind\": \"contract|product\", \"suggestedName\": \"...\", \"role\": \"...\" } ] }`. `kind` is optional and inferred from the document's own `kind:` field when omitted. `content` must be a FULL document, never a fragment.","operationId":"applyBundle","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Every member was created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Empty bundle, malformed body, or a member was rejected (nothing persisted)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"artifact.bundle","description":"Create several related artifacts atomically"}],"x-since":"8.19.0"}},"/v4/ai/suggest":{"post":{"tags":["AI"],"summary":"Suggest text for a free-text artifact field","description":"**Since v7.28.0** — Server-side proxy to the configured AI model: generates a short suggestion for a free-text field (currently description) from the supplied artifact context. A non-empty currentValue is treated as \"improve this\". The model API key never reaches the client; failures return a non-500 { error } envelope.","operationId":"suggest","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiSuggestRequest"}}},"required":true},"responses":{"200":{"description":"{ suggestion: string }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT bearer token","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"Upstream/model failure — { error: string }","content":{"*/*":{"schema":{"type":"object"}}}},"503":{"description":"AI disabled or not configured — { error: string }","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"ai.suggest","description":"Suggest text for a free-text artifact field"}],"x-since":"7.28.0"}},"/v4/admin/users/{id}/reset-password":{"post":{"tags":["Administration"],"summary":"Reset a user's password (v4 admin)","description":"**Since v9.58.0** — Rotates the target user's password in both stores — the local BCrypt hash and the Keycloak credential — and evicts their cached authentication so the old password stops working immediately. Body `{\"newPassword\": \"...\"}`, or an empty body to have a strong password generated and returned **exactly once**. The owner account cannot be reset through this API. Bearer-only: an admin X-API-KEY is not accepted on /v4.","operationId":"resetUserPassword","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"responses":{"200":{"description":"Password reset; a generated password is shown once","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Supplied password shorter than 8 characters","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required, or the target is the owner account","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.password.reset","description":"Reset another user's password (admin)"}],"x-since":"9.58.0"}},"/v4/admin/users/{id}/messages":{"post":{"tags":["Administration"],"summary":"Send a message to a user (v4 admin)","description":"**Since v9.82.0** — Sends the user an internal message that appears in their Workbench notifications and inbox, with an email copy whose subject is prefixed `[Workbench]`. Body `{ subject, body, creditGrant?: { amount, note? } }`. When `creditGrant` is present the Credits are granted through the same path as `POST /v4/credits/grant`, atomically with the message: if the grant fails nothing is persisted and no email is sent. If the email fails the message and the grant still stand and `emailSent` is false. One activity-log line is written. Bearer-only: an admin X-API-KEY is not accepted on /v4.","operationId":"sendMessage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMessageRequest"}}}},"responses":{"201":{"description":"UserMessageResponse with `balance` when Credits were granted and `emailSent`","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Blank subject or body, or a non-positive creditGrant.amount","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.message.send","description":"Send a user an internal message with an email copy and an optional credit grant (admin)"}],"x-since":"9.82.0"}},"/v4/admin/users/{id}/enable":{"post":{"tags":["Administration"],"summary":"Re-enable a user account (v4 admin)","description":"**Since v9.59.0** — Clears the account's disabled state and sets Keycloak `enabled=true`. Deleted OAuth authorizations are not restored — the user signs in again.","operationId":"enableUser","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Account re-enabled","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Account is not disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.enable","description":"Re-enable a disabled user account (admin)"}],"x-since":"9.59.0"}},"/v4/admin/users/{id}/disable":{"post":{"tags":["Administration"],"summary":"Disable a user account (v4 admin)","description":"**Since v9.59.0** — Switches an account off across all four authentication paths: the local `disabled_at` column checked on every request, the auth-cache eviction, the Keycloak `enabled` flag, and a sweep of the account's live OAuth authorizations so tokens already issued stop working immediately. Reversible with `/enable`. An admin cannot disable their own account, and the owner account cannot be disabled at all. The response reports each path's outcome rather than only that the call succeeded.","operationId":"disableUser","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"responses":{"200":{"description":"Account disabled; the response names what each enforcement path did","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"An admin attempted to disable their own account","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required, or the target is the owner account","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Account is already disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.disable","description":"Disable a user account (admin)"}],"x-since":"9.59.0"}},"/v4/admin/users/{id}/api-key/rotate":{"post":{"tags":["Administration"],"summary":"Rotate a user's API key (v4 admin)","description":"**Since v9.49.0** — Replaces the target user's API key and returns the new value **exactly once**. The previous key stops working immediately, including on requests that would otherwise have been served from the auth cache. Intended for responding to an exposed key without a direct write to the production database.","operationId":"rotateUserApiKey","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Key rotated; the new key is shown once","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.apikey.rotate","description":"Rotate another user's API key (admin)"}],"x-since":"9.49.0"}},"/v4/admin/test-runs/mutes":{"get":{"tags":["Administration"],"summary":"List test-suite alert mutes (admin)","description":"**Since v9.117.11** — Active mutes by default; `history=true` returns every mute ever made, including unmuted ones, with who and when for both.","operationId":"mutes","parameters":[{"name":"history","in":"query","description":"Include unmuted (closed) mutes","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Mutes, newest first","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.testRuns.listMutes","description":"List test-suite alert mutes"}],"x-since":"9.117.11"},"post":{"tags":["Administration"],"summary":"Mute alerts on one test suite (admin)","description":"**Since v9.117.11** — Stops alert emails for one suite. `app`, `process` and `reason` are required; the admin and the time are recorded. A suite can have one active mute.","operationId":"mute","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestRunMuteRequest"}}},"required":true},"responses":{"201":{"description":"The mute, as recorded","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"400":{"description":"Suite not named, or no reason given","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"409":{"description":"The suite is already muted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.testRuns.mute","description":"Mute alerts on one test suite, with a reason"}],"x-since":"9.117.11"},"delete":{"tags":["Administration"],"summary":"Unmute alerts on one test suite (admin)","description":"**Since v9.117.11** — Closes the suite's active mute, recording the admin and the time. The mute row is kept as history. If the suite is still failing, the next hourly pass alerts.","operationId":"unmute","parameters":[{"name":"app","in":"query","description":"The suite's diagnostics `app`","required":true,"schema":{"type":"string"}},{"name":"process","in":"query","description":"The suite's `source.process`","required":true,"schema":{"type":"string"}},{"name":"provenance","in":"query","description":"The runs' provenance, if any","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The closed mute","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"400":{"description":"Suite not named","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}},"404":{"description":"The suite is not muted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRunSuiteMute"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.testRuns.unmute","description":"Unmute alerts on one test suite"}],"x-since":"9.117.11"}},"/v4/admin/test-runs/alerts/test":{"post":{"tags":["Administration"],"summary":"Send a test alert to every admin (admin)","description":"**Since v9.117.11** — Sends a clearly labelled test email through the exact path real alerts use, and reports per recipient whether the mail server accepted it.","operationId":"sendTestAlert","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"`{recipients: [{email, sent}]}`","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.testRuns.testAlert","description":"Send a test alert to every admin to prove delivery"}],"x-since":"9.117.11"}},"/v4/admin/signup-requests/{id}/resend":{"post":{"tags":["Administration"],"summary":"Re-send a signup-request approval email","description":"**Since v8.13.0** — Re-sends the approval email for an approved request. A still-valid invitation code is re-sent as-is (codeStatus=reused); an expired or exhausted code is re-minted first — fresh single-use 14-day code, old one revoked — and the new code is sent (codeStatus=re-minted, #1000). Throttled to at most one send per minute. Returns 409 if the request is not approved, 404 if unknown, 429 if within the throttle window.","operationId":"resend","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Resend attempted; body carries the request plus codeStatus=reused|re-minted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Request is not in the approved state","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Within the resend throttle window","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.resend","description":"Re-send the approval email for an approved signup request"}],"x-since":"8.13.0"}},"/v4/admin/signup-requests/{id}/reject":{"post":{"tags":["Administration"],"summary":"Reject a signup request","description":"**Since v7.13.0** — Marks the request rejected. Pass {\"sendEmail\": true} to email the requester a polite decline.","operationId":"reject_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"responses":{"200":{"description":"Rejected","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Already reviewed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.reject","description":"Reject a signup request"}],"x-since":"7.13.0"}},"/v4/admin/signup-requests/{id}/approve":{"post":{"tags":["Administration"],"summary":"Approve a signup request","description":"**Since v7.13.0** — Marks the request approved and emails the requester a sign-up link. Idempotent — approving an already-reviewed request returns 409.","operationId":"approve_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"Approved","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Already reviewed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.approve","description":"Approve a signup request"}],"x-since":"7.13.0"}},"/v4/admin/signing/backfill":{"post":{"tags":["Administration"],"summary":"Backfill auto-sign for an organization (v4 admin)","description":"**Since v8.2.0** — Re-signs an organization's pre-existing artifacts that should be signed but are not — closing the #904 gap where artifacts created before the org enabled auto-sign (or before #855 shipped) were never signed, since auto-sign only fires on the next save. Reuses the exact auto-sign-on-save gate + credential resolution + per-artifact opt-out, so nothing signs that a normal save would not. Idempotent: already-signed rows are skipped (never re-signed) and customProperties autosign=false rows are respected. Operates on the latest version of each contract and product; prior versions are not touched. Pass org or orgId, and dryRun=true to only classify without signing (the #904 AC-1 enumeration).","operationId":"backfillSigning","parameters":[{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"dryRun","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Backfill report (SigningBackfillResult)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Neither org nor orgId supplied","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.signing.backfill","description":"Backfill-sign an org's unsigned artifacts"}],"x-since":"8.2.0"}},"/v4/admin/plugins/disable":{"post":{"tags":["Administration"],"summary":"Disable a plugin","description":"**Since v9.3.0** — Records a veto on a plugin. Body: {\"pluginId\": \"<reverse-DNS id>\", \"orgSlug\": \"<org>\" (optional — omit for platform-wide), \"reason\": \"<shown to the org admin>\"}. The veto always wins over an org's activation. platform-admin only.","operationId":"disable","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"The recorded veto","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing pluginId","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Unknown orgSlug","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.plugins.disable","description":"Veto a plugin platform-wide or for one organization"}],"x-since":"9.3.0"},"delete":{"tags":["Administration"],"summary":"Lift a plugin veto","description":"**Since v9.3.0** — Removes a veto. This enables nothing on its own — whether the plugin then contributes is the organization's own activation decision. Body: {\"pluginId\": \"<reverse-DNS id>\", \"orgSlug\": \"<org>\" (optional — omit for the platform-wide veto)}. platform-admin only.","operationId":"lift","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"204":{"description":"Veto lifted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing pluginId","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Unknown orgSlug, or no such veto","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.plugins.lift","description":"Lift a veto on a plugin"}],"x-since":"9.3.0"}},"/v4/admin/invitation-codes":{"get":{"tags":["Administration"],"summary":"List all admin invitation codes","description":"**Since v7.13.0** — Returns all admin-minted invitation codes with computed isExpired and isExhausted flags.","operationId":"list_6","responses":{"200":{"description":"List of codes","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.list","description":"List all admin invitation codes"}],"x-since":"7.13.0"},"post":{"tags":["Administration"],"summary":"Mint a new admin invitation code","description":"**Since v7.13.0** — Admin-minted code for events, partners, etc. Server validates uniqueness across personal and admin tables. If 'code' is omitted, the server auto-generates one.","operationId":"mint","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Created code","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Bad request","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Duplicate code","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.mint","description":"Mint a new admin invitation code"}],"x-since":"7.13.0"}},"/v4/admin/emails/{id}/resend":{"post":{"tags":["Administration"],"summary":"Re-send a logged email (v4 admin)","description":"**Since v7.27.0** — Re-sends a logged email's stored recipient/subject/body (#653). The new attempt is recorded as a fresh email-log row by the send pipeline. Rows logged before the body column existed cannot be resent (409).","operationId":"resendEmail","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"Resend attempted; `sent` reports the outcome","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No email log entry with this id","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Original body not retained; cannot resend","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.email-log.resend","description":"Re-send a logged email (admin)"}],"x-since":"7.27.0"}},"/v4/admin/demo/push":{"post":{"tags":["Administration"],"summary":"Push the demo set to every account","description":"**Since v9.108.0** — Brings every account's demo artifacts up to the **live `demo` org's** set, skipping anyone who has made theirs their own.\n\n**`dryRun` defaults to `true`.** The safe call is the short one — an admin must pass `dryRun=false` for any bytes to move. A dry run classifies and counts exactly as a real push would and is recorded like one, so the numbers a panel showed are the numbers the confirm produces.\n\n**Decisions are per artifact; counts are per account.** An account is counted once, under the most cautious state among its artifacts, so one holding a pristine and an edited file counts as *Modified* and still has its pristine file updated.\n\n| State | Action |\n|---|---|\n| Pristine | updated when `updatePristine` (default on) — `UNCHANGED` if already identical |\n| Modified | **skipped, always.** Not overridable by any parameter |\n| Deleted | skipped unless `alsoRestoreDeleted` |\n| Unknown | **the whole account is skipped.** Seeded before provenance existed, so \"never received\" cannot be told from \"deleted long ago\"; pushing would resurrect artifacts those users deleted. They are served by the user-triggered import instead |\n| Never received | created |\n\nAn unreachable or empty source aborts with **503** and nothing written.","operationId":"push","parameters":[{"name":"dryRun","in":"query","description":"Classify and count, writing nothing. Defaults to true.","required":false,"schema":{"type":"boolean","default":true}},{"name":"updatePristine","in":"query","description":"Bring pristine copies up to the source. Defaults to true.","required":false,"schema":{"type":"boolean","default":true}},{"name":"alsoRestoreDeleted","in":"query","description":"Also restore copies the user deliberately deleted. Defaults to false — see #1346 AC-10.","required":false,"schema":{"type":"boolean","default":false}},{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The push report — per-bucket account counts and per-artifact outcomes","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"503":{"description":"The demo source org is missing, unreadable or empty — nothing written","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"demo.push","description":"Push the live demo set to every account, skipping anyone who changed theirs"}],"x-since":"9.108.0"}},"/v4/admin/blocked-domains":{"get":{"tags":["Administration"],"summary":"List blocked domains","description":"**Since v7.13.0** — Returns all blocked email domains.","operationId":"listBlockedDomains","responses":{"200":{"description":"List of blocked domains","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"blocked-domain.list","description":"List blocked email domains"}],"x-since":"7.13.0"},"post":{"tags":["Administration"],"summary":"Block a domain","description":"**Since v7.13.0** — Adds an email domain to the blocklist.","operationId":"blockDomain","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional. Opaque, client-generated value (≤ 255 chars). When supplied, the server caches the response of the first successful invocation and replays it on a retry with the same key. Scoped to (user, method, path). TTL configurable via bitol.idempotency.ttl-minutes (default 60).","required":false,"schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Domain blocked successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain already blocked or invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"blocked-domain.create","description":"Add an email domain to the blocklist"}],"x-since":"7.13.0"}},"/v3/products":{"get":{"tags":["Products"],"summary":"List product headers (v3)","description":"**Since v3.0.0** — Returns header fields for all products. Pass org or orgId to list organization products.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_4","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of product header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.list","description":"List data product headers"}],"x-since":"3.0.0","x-sunset":"2027-01-01"},"post":{"tags":["Products"],"summary":"Upload a data product (v3)","description":"**Since v3.0.0** — Uploads an ODPS YAML data product file directly. Pass org or orgId to upload to an organization's storage.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_6","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractVersion","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Product uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload error","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid file type","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.upload","description":"Upload an ODPS YAML data product file"}],"x-since":"3.0.0","x-sunset":"2027-01-01"},"delete":{"tags":["Products"],"summary":"Delete a data product (v3)","description":"**Since v3.0.0** — Soft-deletes a specific product version. Pass org or orgId for organization products.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_6","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product version"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/products/publish-github":{"post":{"tags":["Products"],"summary":"Publish product to GitHub (v3 — enhanced)","description":"**Since v2.6.1** — Enhanced publish with pre-publish version check, Git tagging, and auto-publish of referenced contracts. Compares local content against the last published version (via scoped Git tags). Returns SKIP if identical, CONFLICT (409) if version not bumped, or publishes and tags on success. Referenced contracts from outputPorts/inputPorts are automatically checked and published. Pass org, orgId, or orgSlug to publish from an organization's storage using the org's GitHub token.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_4","parameters":[{"name":"productId","in":"query","description":"UUID of the data product to publish","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Semantic version of the product to publish (e.g. 1.2.3). Defaults to the product's current version when omitted.","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"GitHub branch to publish to. Defaults to the branch encoded in the product's canonicalUrl, falling back to the repo's default branch.","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","description":"Force publish — skip pre-publish version conflict check","required":false,"schema":{"type":"string"}},{"name":"orgSlug","in":"query","description":"Deprecated — use 'org' instead. Organization slug (legacy parameter, kept for backward compatibility).","required":false,"deprecated":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug (canonical). Takes precedence over 'orgSlug' when both are present.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org and orgSlug)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product published (or skipped if identical). Includes tag, skipped flag, and per-contract results","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token, missing canonicalUrl, or invalid GitHub URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Version conflict — product or referenced contract version not bumped. Returns per-contract details when contracts conflict","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.publish","description":"Publish a data product to GitHub"}],"x-since":"2.6.1","x-sunset":"2027-01-01"}},"/v3/maturity-history/capture":{"post":{"tags":["Maturity History"],"summary":"Trigger maturity snapshot capture (admin)","description":"**Since v4.4.28** — Admin-only. Immediately captures a maturity snapshot for today by scanning all contract and product files across all users and organizations. Requires Bearer JWT with admin privileges.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"captureSnapshot_1","responses":{"200":{"description":"Snapshot captured","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.history.capture","description":"Trigger maturity snapshot capture"}],"x-since":"4.4.28","x-sunset":"2027-01-01"}},"/v3/github/workflow":{"post":{"tags":["Automation"],"summary":"Install GitHub Actions workflow","description":"**Since v3.2.3** — Installs the upload-data-products workflow file in the specified repository.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"installWorkflow_1","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workflow installed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.workflow.install","description":"Install GitHub Actions workflow"}],"x-since":"3.2.3","x-sunset":"2027-01-01"}},"/v3/github/secrets":{"post":{"tags":["Automation"],"summary":"Set repository secrets","description":"**Since v3.2.3** — Sets encrypted repository secrets for Zeenea integration.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setSecrets_1","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Secrets set","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token, invalid repo URL, or no secrets provided","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.secrets.update","description":"Set repository secrets"}],"x-since":"3.2.3","x-sunset":"2027-01-01"}},"/v3/github/actions/trigger":{"post":{"tags":["Automation"],"summary":"Trigger workflow dispatch","description":"**Since v3.2.3** — Triggers a workflow_dispatch event for the upload workflow.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"triggerWorkflow_1","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workflow triggered","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.workflow.trigger","description":"Trigger a workflow dispatch"}],"x-since":"3.2.3","x-sunset":"2027-01-01"}},"/v3/contracts":{"get":{"tags":["Contracts"],"summary":"List contract headers (v3)","description":"**Since v3.0.0** — Returns header fields for all contracts. Pass org or orgId to list organization contracts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_5","parameters":[{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of contract header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.list","description":"List contract headers"}],"x-since":"3.0.0","x-sunset":"2027-01-01"},"post":{"tags":["Contracts"],"summary":"Upload a data contract (v3)","description":"**Since v3.0.0** — Uploads an ODCS YAML file, a SQL DDL file, or creates a contract from a live JDBC database. Pass org or orgId to store in an organization's storage.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_7","parameters":[{"name":"contractId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sourceFormat","in":"query","required":false,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"ddlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"dbmlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeViews","in":"query","description":"When sourceFormat=jdbc, also introspect database views (#185 TD-5). Views are added as SchemaObjects tagged 'view'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"includeRoutines","in":"query","description":"When sourceFormat=jdbc, also discover stored procedures and functions (#186 TD-6). Attached as JSON customProperties 'storedProcedures' and 'storedFunctions'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"jdbcConnection":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}}}}},"responses":{"200":{"description":"Contract uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported source format or invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload or processing error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.create","description":"Upload a data contract"}],"x-since":"3.0.0","x-sunset":"2027-01-01"},"delete":{"tags":["Contracts"],"summary":"Delete a data contract (v3)","description":"**Since v3.0.0** — Soft-deletes a specific contract version. Pass org or orgId for organization contracts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_7","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract is referenced by data products","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete a data contract"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/contracts/transfer":{"post":{"tags":["Contracts"],"summary":"Transfer artifacts from personal to org storage (v3)","description":"**Since v3.0.0** — Moves contracts and/or products from personal storage into the organization. Requires org or orgId parameter. Transfer is all-or-nothing.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"transferArtifacts_2","parameters":[{"name":"org","in":"query","description":"Organization slug (required for transfer)","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (required for transfer)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TransferItem"}}}},"required":true},"responses":{"200":{"description":"Artifacts transferred successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Validation failed or no org specified","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File transfer error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.transfer","description":"Transfer artifacts to org storage"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/contracts/test-connection":{"post":{"tags":["Contracts"],"summary":"Test JDBC database connection (v3)","description":"**Since v3.0.0** — Tests connectivity to a database without introspecting the schema.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testConnection_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result (status: ok or error)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing required parameters","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.database.test","description":"Test JDBC database connection"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/contracts/publish-github":{"post":{"tags":["Contracts"],"summary":"Publish contract to GitHub (v3 — enhanced)","description":"**Since v2.6.1** — Enhanced publish with pre-publish version check and Git tagging. Compares local content against the last published version (via scoped Git tags). Returns SKIP if identical, CONFLICT (409) if version not bumped, or publishes and tags on success. Pass org, orgId, or orgSlug to publish from an organization's storage using the org's GitHub token.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_5","parameters":[{"name":"contractId","in":"query","description":"UUID of the data contract to publish","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Semantic version of the contract to publish (e.g. 1.2.3). Defaults to the contract's current version when omitted.","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"GitHub branch to publish to. Defaults to the branch encoded in the contract's canonicalUrl, falling back to the repo's default branch.","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","description":"Storage mode for the source file (\"permanent\" or \"draft\"). Defaults to permanent.","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"force","in":"query","description":"Force publish — skip pre-publish version conflict check","required":false,"schema":{"type":"string"}},{"name":"orgSlug","in":"query","description":"Deprecated — use 'org' instead. Organization slug (legacy parameter, kept for backward compatibility).","required":false,"deprecated":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug (canonical). Takes precedence over 'orgSlug' when both are present.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org and orgSlug)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract published (or skipped if identical). Includes tag and skipped flag","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token, missing canonicalUrl, or invalid GitHub URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Version conflict — content changed but version not bumped. Returns localVersion, githubVersion, suggestedVersion, and diffs","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.publish","description":"Publish contract to GitHub"}],"x-since":"2.6.1","x-sunset":"2027-01-01"}},"/v3/catalogs/datasets/{datasetId}/import":{"post":{"tags":["External Catalogs"],"summary":"Import a dataset from an external catalog as a data contract","description":"**Since v4.4.0** — Fetches full dataset metadata from the catalog and generates an ODCS data contract. The contract is saved to disk and can be edited in the Workbench editor.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"importDataset_1","parameters":[{"name":"datasetId","in":"path","description":"Dataset ID in the external catalog","required":true,"schema":{"type":"string"}},{"name":"vendor","in":"query","description":"Catalog vendor (e.g., zeenea)","required":true,"schema":{"type":"string"}},{"name":"name","in":"query","description":"Override contract name","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract created successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown vendor","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Catalog credentials not configured","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract already exists for this dataset","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"Upstream catalog API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"catalog.dataset.import","description":"Import a catalog dataset as a data contract"}],"x-since":"4.4.0","x-sunset":"2027-01-01"}},"/v2/users/me/integrations/{key}/test":{"post":{"tags":["Publishing"],"summary":"Test integration credentials","description":"**Since v2.12.0** — Tests the stored credentials for the specified integration. Always returns 200; check 'success' field.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testCredentials_2","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test GitHub integration credentials"},{"name":"integration.zeenea.test","description":"Test Zeenea integration credentials"},{"name":"integration.kafka.test","description":"Test Control Center integration credentials"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/users/me/integrations/{key}/test/field/{fieldName}":{"post":{"tags":["Publishing"],"summary":"Test a single integration field","description":"**Since v2.13.0** — Tests a specific field value without saving. Returns success/message/warning. Uses context or stored credentials for fields that require companion values.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testField_2","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"fieldName","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Test result (check 'success' field)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration or field name","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test a single GitHub integration field"},{"name":"integration.zeenea.test","description":"Test a single Zeenea integration field"},{"name":"integration.kafka.test","description":"Test a single Control Center integration field"}],"x-since":"2.13.0","x-sunset":"2027-01-01"}},"/v2/reference-tags":{"get":{"tags":["Tags"],"summary":"List all reference tags (v2)","description":"**Since v2.4.2** — Returns all reference tags created by the authenticated user\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listTags_1","responses":{"200":{"description":"List of reference tags","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.list","description":"List all reference tags"}],"x-since":"2.4.2","x-sunset":"2027-01-01"},"post":{"tags":["Tags"],"summary":"Create a reference tag (v2)","description":"**Since v2.4.2** — Creates a new reference tag with the specified properties\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"createTag_1","parameters":[{"name":"tagName","in":"query","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string","default":""}}],"responses":{"201":{"description":"Tag created successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request or tag already exists","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.create","description":"Create a reference tag"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/products":{"get":{"tags":["Products"],"summary":"List product headers (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/products instead. Returns header fields for all data products belonging to the authenticated user.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_6","responses":{"200":{"description":"JSON array of product header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.list","description":"List data product headers"}],"x-since":"2.2.0","x-sunset":"2027-01-01"},"post":{"tags":["Products"],"summary":"Upload a data product (v2)","description":"**Since v2.2.0** — Deprecated — use POST /v3/products (multipart) instead. Uploads an ODPS YAML data product file directly.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_8","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractVersion","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Product uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload error","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid file type","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.upload","description":"Upload an ODPS YAML data product file"}],"x-since":"2.2.0","x-sunset":"2027-01-01"},"delete":{"tags":["Products"],"summary":"Delete a data product (v2)","description":"**Since v2.2.0** — Deprecated — use DELETE /v3/products instead. Soft-deletes a specific product version.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_8","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product version"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/products/publish-github":{"post":{"tags":["Products"],"summary":"Publish product to GitHub (v2)","description":"**Since v2.2.0** — Deprecated — use POST /v3/products/publish-github instead. Pushes the product YAML to GitHub using the canonicalUrl.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_6","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product published to GitHub","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token or canonicalUrl","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.publish","description":"Publish a data product to GitHub"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/pdf-settings":{"post":{"tags":["Publishing"],"summary":"Update PDF settings (v2)","description":"**Since v2.4.0** — Updates PDF rendering settings (page size and footer message).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updatePdfSettings_2","parameters":[{"name":"size","in":"query","required":true,"schema":{"type":"string"}},{"name":"footer","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PDF settings updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to update settings file","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"pdf-settings.update","description":"Update PDF rendering settings"}],"x-since":"2.4.0","x-sunset":"2027-01-01"}},"/v2/orgs":{"post":{"tags":["Organizations"],"summary":"Create an organization","description":"**Since v2.3.0** — Creates a new organization with the given name, slug, and optional domains. The authenticated user becomes the creator.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"createOrg_1","parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string"}},{"name":"slug","in":"query","required":true,"schema":{"type":"string"}},{"name":"domains","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"201":{"description":"Organization created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid slug, duplicate slug, or domain already claimed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.create","description":"Create a new organization"}],"x-since":"2.3.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/settings/pdf-settings":{"post":{"tags":["Organization Settings"],"summary":"Update organization PDF settings","description":"**Since v2.7.0** — Updates PDF rendering settings (page size, footer) for the organization. Requires ADMIN+ role.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"updatePdfSettings_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"size","in":"query","required":true,"schema":{"type":"string"}},{"name":"footer","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PDF settings updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to update settings","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.pdf.update","description":"Update organization PDF rendering settings"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/settings/logo":{"get":{"tags":["Organization Settings"],"summary":"Get organization logo","description":"**Since v2.7.0** — Returns the organization's current SVG logo. Requires org membership.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getLogo_2","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SVG logo content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found or no logo","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.logo.get","description":"Get the organization logo"}],"x-since":"2.7.0","x-sunset":"2027-01-01"},"post":{"tags":["Organization Settings"],"summary":"Upload organization logo","description":"**Since v2.7.0** — Uploads an SVG logo for the organization's PDF contract renderings. Requires ADMIN+ role.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"uploadLogo_2","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Uploaded file is not a valid SVG","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Logo already exists (use force=true)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File I/O error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.logo.upload","description":"Upload the organization logo"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/products":{"get":{"tags":["Organization Products"],"summary":"List organization product headers","description":"**Since v2.5.0** — Deprecated — use GET /v3/products?org={slug} instead. Returns header fields for all products in the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_7","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of product headers","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.list","description":"List data product headers"}],"x-since":"2.5.0","x-sunset":"2027-01-01"},"post":{"tags":["Organization Products"],"summary":"Upload a product to the organization","description":"**Since v2.5.0** — Deprecated — use POST /v3/products?org={slug} (multipart) instead. Uploads an ODPS YAML file directly to the organization's storage.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_9","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractVersion","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Product uploaded","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Product creation error","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid file type","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.upload","description":"Upload an ODPS YAML data product file"}],"x-since":"2.5.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Products"],"summary":"Delete an organization product","description":"**Since v2.5.0** — Deprecated — use DELETE /v3/products?org={slug} instead. Soft-deletes a specific product version from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_9","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product deleted","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product version"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/products/publish-github":{"post":{"tags":["Organization Products"],"summary":"Publish organization product to GitHub","description":"**Since v2.5.0** — Deprecated — use POST /v3/products/publish-github?org={slug} instead. Pushes the product YAML to GitHub.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_7","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product published","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token or canonicalUrl","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.publish","description":"Publish a data product to GitHub"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/join":{"post":{"tags":["Membership"],"summary":"Request to join an organization","description":"**Since v2.5.0** — Submits a join request that must be approved by an org admin or owner.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"joinRequest_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"message","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"Join request created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Already a member or pending request exists","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.join","description":"Request to join an organization"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/invite":{"post":{"tags":["Membership"],"summary":"Invite a user to the organization","description":"**Since v2.5.0** — Admin/owner invites a user by email. The user must accept the invitation.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"invite_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"message","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"Invitation created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Already a member or pending invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.invite","description":"Invite a user to the organization"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/integrations/{key}/test":{"post":{"tags":["Organization Settings"],"summary":"Test org integration credentials","description":"**Since v2.12.0**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testCredentials_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test org GitHub integration credentials"},{"name":"integration.zeenea.test","description":"Test org Zeenea integration credentials"},{"name":"integration.kafka.test","description":"Test org Control Center integration credentials"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/integrations/{key}/test/field/{fieldName}":{"post":{"tags":["Organization Settings"],"summary":"Test a single org integration field","description":"**Since v2.13.0** — Tests a specific field value without saving. Returns success/message/warning. Uses context or stored credentials for fields that require companion values.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testField_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"fieldName","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Test result (check 'success' field)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown integration or field name","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role (requires ADMIN+)","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.github.test","description":"Test a single org GitHub integration field"},{"name":"integration.zeenea.test","description":"Test a single org Zeenea integration field"},{"name":"integration.kafka.test","description":"Test a single org Control Center integration field"}],"x-since":"2.13.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/domains":{"post":{"tags":["Organizations"],"summary":"Add domain to organization","description":"**Since v2.7.0** — Adds an email domain to the organization for discovery. Requires ADMIN+ role.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"addDomain_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"domain","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Domain added","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain blocked or already claimed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.domain.create","description":"Add an email domain to the organization"}],"x-since":"2.7.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organizations"],"summary":"Remove domain from organization","description":"**Since v2.7.0** — Removes an email domain from the organization. Requires ADMIN+ role.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeDomain_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"domain","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain not found or doesn't belong to this org","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.domain.delete","description":"Remove an email domain from the organization"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/contracts":{"get":{"tags":["Organization Contracts"],"summary":"List organization contract headers","description":"**Since v2.5.0** — Deprecated — use GET /v3/contracts?org={slug} instead. Returns header fields for all contracts in the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_8","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"JSON array of contract headers","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.list","description":"List organization contract headers"}],"x-since":"2.5.0","x-sunset":"2027-01-01"},"post":{"tags":["Organization Contracts"],"summary":"Upload a contract to the organization","description":"**Since v2.5.0** — Deprecated — use POST /v3/contracts?org={slug} instead. Uploads an ODCS YAML or DDL file to the organization's storage. Requires org membership.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_10","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sourceFormat","in":"query","required":false,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"ddlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"dbmlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeViews","in":"query","description":"When sourceFormat=jdbc, also introspect database views (#185 TD-5). Views are added as SchemaObjects tagged 'view'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"includeRoutines","in":"query","description":"When sourceFormat=jdbc, also discover stored procedures and functions (#186 TD-6). Attached as JSON customProperties 'storedProcedures' and 'storedFunctions'. Default false.","required":false,"schema":{"type":"boolean","default":false}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"jdbcConnection":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}}}}},"responses":{"200":{"description":"Contract uploaded","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.create","description":"Upload a contract to the organization"}],"x-since":"2.5.0","x-sunset":"2027-01-01"},"delete":{"tags":["Organization Contracts"],"summary":"Delete an organization contract","description":"**Since v2.5.0** — Deprecated — use DELETE /v3/contracts?org={slug} instead. Soft-deletes a specific contract version from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_10","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Contract deleted","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete an organization contract"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/contracts/transfer":{"post":{"tags":["Organization Contracts"],"summary":"Transfer artifacts from personal to org storage","description":"**Since v2.5.1** — Deprecated — use POST /v3/contracts/transfer?org={slug} instead. Moves contracts and/or products from the authenticated user's personal storage into the organization. Transfer is all-or-nothing: if any item fails validation, nothing is transferred. The request body is a JSON array of TransferItem objects.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"transferArtifacts_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TransferItem"}}}},"required":true},"responses":{"200":{"description":"Artifacts transferred successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Validation failed (missing artifacts, invalid types)","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File transfer error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.transfer","description":"Transfer artifacts to org storage"}],"x-since":"2.5.1","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/contracts/publish-github":{"post":{"tags":["Organization Contracts"],"summary":"Publish organization contract to GitHub","description":"**Since v2.5.0** — Deprecated — use POST /v3/contracts/publish-github?org={slug} instead. Pushes the contract YAML to GitHub. Uses the organization's GitHub token if configured.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_8","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"Contract published","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token or canonicalUrl","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.publish","description":"Publish organization contract to GitHub"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/logo":{"get":{"tags":["Publishing"],"summary":"Get logo (v2)","description":"**Since v2.4.0** — Returns the user's current SVG logo. User identified from JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getLogo_3","responses":{"200":{"description":"SVG logo content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No logo found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"logo.get","description":"Get the user's SVG logo"}],"x-since":"2.4.0","x-sunset":"2027-01-01"},"post":{"tags":["Publishing"],"summary":"Upload a logo (v2)","description":"**Since v2.4.0** — Uploads an SVG logo for PDF contract renderings. Use force=true to overwrite an existing logo.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"uploadLogo_3","parameters":[{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Uploaded file is not a valid SVG","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Logo already exists (use force=true to overwrite)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File I/O error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"logo.upload","description":"Upload an SVG logo"}],"x-since":"2.4.0","x-sunset":"2027-01-01"}},"/v2/github/workflow":{"post":{"tags":["Automation"],"summary":"Install GitHub Actions workflow (v2)","description":"**Since v2.4.2** — Deprecated — use POST /v3/github/workflow instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"installWorkflow_2","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}}],"responses":{"200":{"description":"Workflow installed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.workflow.install","description":"Install GitHub Actions workflow"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/github/secrets":{"post":{"tags":["Automation"],"summary":"Set repository secrets (v2)","description":"**Since v2.4.2** — Deprecated — use POST /v3/github/secrets instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"setSecrets_2","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Secrets set","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token, invalid repo URL, or no secrets provided","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.secrets.update","description":"Set repository secrets"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/github/actions/trigger":{"post":{"tags":["Automation"],"summary":"Trigger workflow dispatch (v2)","description":"**Since v2.4.2** — Deprecated — use POST /v3/github/actions/trigger instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"triggerWorkflow_2","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}}],"responses":{"200":{"description":"Workflow triggered","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.workflow.trigger","description":"Trigger a workflow dispatch"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/contracts":{"get":{"tags":["Contracts"],"summary":"List contract headers (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/contracts instead. Returns header fields for all contracts belonging to the authenticated user.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"readHeaders_9","parameters":[{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"JSON array of contract header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.list","description":"List contract headers"}],"x-since":"2.2.0","x-sunset":"2027-01-01"},"post":{"tags":["Contracts"],"summary":"Upload a data contract (v2)","description":"**Since v2.2.0** — Deprecated — use POST /v3/contracts instead. Uploads an ODCS YAML file, a SQL DDL file, or creates a contract from a live JDBC database. For sourceFormat=jdbc, pass connection parameters as a 'jdbcConnection' JSON part to keep credentials out of URLs.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"create_11","parameters":[{"name":"contractId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sourceFormat","in":"query","required":false,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"ddlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"dbmlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeViews","in":"query","description":"When sourceFormat=jdbc, also introspect database views (#185 TD-5). Views are added as SchemaObjects tagged 'view'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"includeRoutines","in":"query","description":"When sourceFormat=jdbc, also discover stored procedures and functions (#186 TD-6). Attached as JSON customProperties 'storedProcedures' and 'storedFunctions'. Default false.","required":false,"schema":{"type":"boolean","default":false}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"jdbcConnection":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}}}}},"responses":{"200":{"description":"Contract uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported source format or invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload or processing error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.create","description":"Upload a data contract"}],"x-since":"2.2.0","x-sunset":"2027-01-01"},"delete":{"tags":["Contracts"],"summary":"Delete a data contract (v2)","description":"**Since v2.2.0** — Deprecated — use DELETE /v3/contracts instead. Soft-deletes a specific contract version.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_11","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Contract deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract is referenced by data products","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete a data contract"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/contracts/test-connection":{"post":{"tags":["Contracts"],"summary":"Test JDBC database connection (v2)","description":"**Since v2.9.0** — Deprecated — use POST /v3/contracts/test-connection instead. Tests connectivity to a database without introspecting the schema. Connection parameters are sent as a JSON request body to keep credentials out of URLs.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"testConnection_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result (status: ok or error)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.database.test","description":"Test JDBC database connection"}],"x-since":"2.9.0","x-sunset":"2027-01-01"}},"/v2/contracts/publish-github":{"post":{"tags":["Contracts"],"summary":"Publish contract to GitHub (v2)","description":"**Since v2.2.0** — Deprecated — use POST /v3/contracts/publish-github instead. Pushes the contract YAML to GitHub using the canonicalUrl.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"publishToGitHub_9","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"Contract published to GitHub","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token or canonicalUrl","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.publish","description":"Publish contract to GitHub"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/admin/signup-requests/{id}/reject":{"post":{"tags":["Administration"],"summary":"Reject a signup request","description":"**Since v2.7.0** — Marks the request rejected. Pass {\"sendEmail\": true} to email the requester a polite decline.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"reject_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"responses":{"200":{"description":"Rejected","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Already reviewed","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.reject","description":"Reject a signup request"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/admin/signup-requests/{id}/approve":{"post":{"tags":["Administration"],"summary":"Approve a signup request","description":"**Since v2.7.0** — Marks the request approved and emails the requester a sign-up link. Idempotent — approving an already-reviewed request returns 409.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"approve_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"Approved","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Already reviewed","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.approve","description":"Approve a signup request"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/admin/invitation-codes":{"get":{"tags":["Administration"],"summary":"List all admin invitation codes","description":"**Since v2.7.0** — Returns all admin-minted invitation codes with computed isExpired and isExhausted flags.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"list_7","responses":{"200":{"description":"List of codes","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.list","description":"List all admin invitation codes"}],"x-since":"2.7.0","x-sunset":"2027-01-01"},"post":{"tags":["Administration"],"summary":"Mint a new admin invitation code","description":"**Since v2.7.0** — Admin-minted code for events, partners, etc. Server validates uniqueness across personal and admin tables. If 'code' is omitted, the server auto-generates one.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"mint_1","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Created code","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Bad request","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Duplicate code","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.mint","description":"Mint a new admin invitation code"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/admin/blocked-domains":{"get":{"tags":["Administration"],"summary":"List blocked domains","description":"**Since v2.6.0** — Returns all blocked email domains.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listBlockedDomains_1","responses":{"200":{"description":"List of blocked domains","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"blocked-domain.list","description":"List blocked email domains"}],"x-since":"2.6.0","x-sunset":"2027-01-01"},"post":{"tags":["Administration"],"summary":"Block a domain","description":"**Since v2.6.0** — Adds an email domain to the blocklist.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"blockDomain_1","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Domain blocked successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain already blocked or invalid input","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"blocked-domain.create","description":"Add an email domain to the blocklist"}],"x-since":"2.6.0","x-sunset":"2027-01-01"}},"/v1/verify-signature":{"post":{"tags":["Verification"],"summary":"Verify signature on uploaded file (public)","description":"**Since v4.4.32** — Accepts an ODCS YAML (.odcs.yaml), ODPS YAML (.odps.yaml), or ZIP bundle (.zip) containing data contracts and/or products. Returns verification results per file. No authentication required.","operationId":"verifyUpload","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Verification result(s)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported file type or invalid content","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"signature.verify","description":"Verify signature on an uploaded file"}],"x-since":"4.4.32"}},"/v1/users/reset-password":{"post":{"tags":["Users"],"summary":"Reset password with code","description":"**Since v2.1.4** — Resets a user's password using the 6-character code received via email. Code expires after 30 minutes. No authentication required.","operationId":"resetPassword","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid or expired code, or password too short","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-since":"2.1.4"}},"/v1/users/resend-verification":{"post":{"tags":["Users"],"summary":"Resend verification email","description":"**Since v1.0.0** — Resends the verification email with the existing validation code. No authentication required. Rate-limited to one request per 2 minutes.","operationId":"resendVerification_1","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification email sent or user already validated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No validation code available","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Too many requests (wait 2 minutes)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to send email","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.resend-verification","description":"Resend the email verification message"}],"x-since":"1.0.0"}},"/v1/users/forgot-password":{"post":{"tags":["Users"],"summary":"Forgot password","description":"**Since v2.1.4** — Sends a password reset code to the specified email address. Always returns 200 to prevent email enumeration. No authentication required.","operationId":"forgotPassword","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"If the email is registered, a reset code has been sent","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Too many reset requests (max 3 per 24 hours)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-since":"2.1.4"}},"/v1/self-report":{"post":{"tags":["Self-Report"],"summary":"Submit a self-report (deprecated)","description":"**Deprecated** — use `POST /v4/self-report` instead. Public Help-tab endpoint; anonymous and signed-in callers both allowed.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"submit_2","parameters":[{"name":"description","in":"query","required":true,"schema":{"type":"string"}},{"name":"context","in":"query","required":false,"schema":{"type":"string"}},{"name":"attachment","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","format":"binary"}}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"deprecated":true,"x-intent":[{"name":"self-report.create","description":"Submit an in-app help/feedback report"}],"x-sunset":"2027-01-01"}},"/v1/reference-tags":{"get":{"tags":["Tags"],"summary":"List all reference tags","description":"**Since v1.0.0** — Returns all reference tags created by the authenticated user","operationId":"listTags_2","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of reference tags","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.list","description":"List all reference tags"}],"x-since":"1.0.0"},"post":{"tags":["Tags"],"summary":"Create a reference tag","description":"**Since v1.0.0** — Creates a new reference tag with the specified properties","operationId":"createTag_2","parameters":[{"name":"tagName","in":"query","required":true,"schema":{"type":"string"}},{"name":"properties","in":"query","required":true,"schema":{"type":"string"}},{"name":"description","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"Tag created successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request or tag already exists","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"reference-tag.create","description":"Create a reference tag"}],"x-since":"1.0.0"}},"/v1/products":{"get":{"tags":["Products"],"summary":"List product headers","description":"**Since v1.0.0** — Returns header fields (id, version, name, domain, tenant, status) for all data products belonging to the authenticated user.","operationId":"readHeaders_10","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of product header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Error reading products from disk","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"product.list","description":"List data product headers"}],"x-since":"1.0.0"},"post":{"tags":["Products"],"summary":"Upload a data product","description":"**Since v1.0.0** — Uploads an ODPS YAML data product file directly. Only .odps.yaml files are accepted.","operationId":"create_12","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractVersion","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Product uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload error","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid file type (must be .odps.yaml)","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"product.upload","description":"Upload an ODPS YAML data product file"}],"x-since":"1.0.0"},"delete":{"tags":["Products"],"summary":"Delete a data product","description":"**Since v1.0.0** — Soft-deletes a specific product version by renaming the file. Requires a validated account.","operationId":"delete_12","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product version"}],"x-since":"1.0.0"}},"/v1/products/publish-github":{"post":{"tags":["Products"],"summary":"Publish product to GitHub","description":"**Since v1.0.0** — Pushes the product YAML to GitHub using the canonicalUrl found in the product's authoritativeDefinitions. Requires a validated account with a GitHub token configured in the user profile.","operationId":"publishToGitHub_10","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product published to GitHub","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token, missing canonicalUrl, or invalid GitHub URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"product.publish","description":"Publish a data product to GitHub"}],"x-since":"1.0.0"}},"/v1/pdf-settings":{"post":{"tags":["Publishing"],"summary":"Update PDF settings","description":"**Since v1.0.0** — Updates PDF rendering settings (page size and footer message) stored as a YAML file in the user's directory.","operationId":"updatePdfSettings_4","parameters":[{"name":"size","in":"query","required":true,"schema":{"type":"string"}},{"name":"footer","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"PDF settings updated successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not activated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Failed to update settings file","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"pdf-settings.update","description":"Update PDF rendering settings"}],"x-since":"1.0.0"}},"/v1/logo":{"get":{"tags":["Publishing"],"summary":"Get logo","description":"**Since v1.0.0** — Returns the user's current SVG logo. Requires a validated account.","operationId":"getLogo_4","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SVG logo content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not activated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No logo found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"logo.get","description":"Get the user's current SVG logo"}],"x-since":"1.0.0"},"post":{"tags":["Publishing"],"summary":"Upload a logo","description":"**Since v1.0.0** — Uploads an SVG logo for the user's PDF contract renderings. If a logo exists, use force=true to overwrite (the old logo is backed up with a timestamp).","operationId":"uploadLogo_4","parameters":[{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Uploaded file is not a valid SVG","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not activated","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Logo already exists (use force=true to overwrite)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File I/O error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"logo.upload","description":"Upload an SVG logo for PDF renderings"}],"x-since":"1.0.0"}},"/v1/github/workflow":{"post":{"tags":["Automation"],"summary":"Install GitHub Actions workflow","description":"**Since v1.0.0** — Installs the upload-data-products workflow file in the specified repository.","operationId":"installWorkflow_3","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"github-action.workflow.install","description":"Install GitHub Actions workflow"}],"x-since":"1.0.0"}},"/v1/github/secrets":{"post":{"tags":["Automation"],"summary":"Set repository secrets","description":"**Since v1.0.0** — Sets encrypted repository secrets for Zeenea integration.","operationId":"setSecrets_3","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"github-action.secrets.update","description":"Set repository secrets"}],"x-since":"1.0.0"}},"/v1/github/actions/trigger":{"post":{"tags":["Automation"],"summary":"Trigger workflow dispatch","description":"**Since v1.0.0** — Triggers a workflow_dispatch event for the upload workflow.","operationId":"triggerWorkflow_3","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string","default":"main"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"github-action.workflow.trigger","description":"Trigger a workflow dispatch"}],"x-since":"1.0.0"}},"/v1/diagnostics":{"get":{"tags":["Diagnostics"],"summary":"List diagnostics reports (admin only)","description":"**Since v3.1.0** — Paginated. Filters: type, email, since, until, resolved, appVersion, search, provenance, app.","operationId":"list_8","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-CLI-KEY","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"type","in":"query","required":false,"schema":{"type":"string"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","required":false,"schema":{"type":"string"}},{"name":"until","in":"query","required":false,"schema":{"type":"string"}},{"name":"resolved","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"appVersion","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"provenance","in":"query","required":false,"schema":{"type":"string"}},{"name":"app","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Paginated list","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid credentials","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"diagnostics.list","description":"List diagnostics reports"}],"x-since":"3.1.0"},"post":{"tags":["Diagnostics"],"summary":"Submit a diagnostics report","description":"**Since v3.1.0** — Unauthenticated. Accepts a single front-end error report.","operationId":"submit_3","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsReportRequest"}}},"required":true},"responses":{"201":{"description":"Report accepted","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Internal error","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"diagnostics.create","description":"Submit a front-end diagnostics report"}],"x-since":"3.1.0"}},"/v1/contracts":{"get":{"tags":["Contracts"],"summary":"List contract headers","description":"**Since v1.0.0** — Returns header fields (id, version, name, domain, tenant, status) for all contracts belonging to the authenticated user.","operationId":"readHeaders_11","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of contract header objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Error reading contracts from disk","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.list","description":"List contract headers"}],"x-since":"1.0.0"},"post":{"tags":["Contracts"],"summary":"Upload a data contract","description":"**Since v1.0.0** — Uploads an ODCS YAML file or a SQL DDL file. DDL files can be uploaded directly or downloaded from a URL via the ddlUrl parameter. Requires a validated account.","operationId":"create_13","parameters":[{"name":"contractId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sourceFormat","in":"query","required":false,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":false,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"ddlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"dbmlUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeViews","in":"query","description":"When sourceFormat=jdbc, also introspect database views (#185 TD-5). Views are added as SchemaObjects tagged 'view'. Default false: tables only.","required":false,"schema":{"type":"boolean","default":false}},{"name":"includeRoutines","in":"query","description":"When sourceFormat=jdbc, also discover stored procedures and functions (#186 TD-6). Results are attached to the contract as JSON customProperties 'storedProcedures' and 'storedFunctions'. Default false.","required":false,"schema":{"type":"boolean","default":false}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"jdbcConnection":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}}}}},"responses":{"200":{"description":"Contract uploaded successfully. ODCS: returns a JSON UploadResult ({message, id, version}). DDL: returns contract header as JSON.","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported source format or invalid input combination","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"422":{"description":"Invalid or malformed contract file (not YAML, unreadable, missing id/version, schema-invalid)","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File upload or processing error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.create","description":"Upload a data contract"}],"x-since":"1.0.0"},"delete":{"tags":["Contracts"],"summary":"Delete a data contract","description":"**Since v1.0.0** — Soft-deletes a specific contract version by renaming the file. Blocked if any data product references the contract. Requires a validated account.","operationId":"delete_13","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract is referenced by one or more data products","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete a data contract"}],"x-since":"1.0.0"}},"/v1/contracts/test-connection":{"post":{"tags":["Contracts"],"summary":"Test JDBC database connection","description":"**Since v2.9.0** — Tests connectivity to a database without introspecting the schema. Connection parameters are sent as a JSON request body to keep credentials out of URLs.","operationId":"testConnection_3","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JdbcConnectionRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result (status: ok or error)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing required parameters","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid credentials","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.database.test","description":"Test JDBC database connection"}],"x-since":"2.9.0"}},"/v1/contracts/publish-github":{"post":{"tags":["Contracts"],"summary":"Publish contract to GitHub","description":"**Since v1.0.0** — Pushes the contract YAML to GitHub using the canonicalUrl found in the contract's authoritativeDefinitions. Requires a validated account with a GitHub token configured in the user profile.","operationId":"publishToGitHub_11","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"branch","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract published to GitHub","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing GitHub token, missing canonicalUrl, or invalid GitHub URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.publish","description":"Publish contract to GitHub"}],"x-since":"1.0.0"}},"/v1/contact":{"post":{"tags":["Contact Sync"],"summary":"Sync a contact to MailerLite","description":"Accepts contact data and syncs to MailerLite. Requires machine-identity auth.","operationId":"syncContact_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactSyncRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contact.transfer","description":"Sync a contact to MailerLite"}]}},"/oauth2/register":{"post":{"tags":["o-auth-2-register-controller"],"operationId":"register_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rfc7591RegistrationRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/v4/users/profile":{"get":{"tags":["Users"],"summary":"Get user profile (v4)","description":"**Since v7.6.0** — Returns the authenticated user's profile. User is identified from JWT — no email param needed.","operationId":"getProfile","responses":{"200":{"description":"UserResponse with profile details","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.profile.get","description":"Get the authenticated user's profile"}],"x-since":"7.6.0"},"patch":{"tags":["Users"],"summary":"Patch user preferences (v4)","description":"**Since v7.6.0** — Partial-update the authenticated user's profile preferences. Supports `inviteDigestOptOut: boolean` (#297), `standardChannel: \"Production\"|\"Previous\"|\"Experimental\"` (#1091), and the public-profile visibility flags `publicProfile: boolean` / `publicCompany: boolean` (#1212). Other fields are ignored.\n\n`publicProfile` governs whether you appear on cross-user surfaces — the leaderboard and, once #1215 ships, a public profile page. It is false for every account created before #1212 and true for signups after it. `publicCompany` governs whether your free-text company is shown when you do appear. A non-boolean value for either is ignored rather than rejected, matching `inviteDigestOptOut`.\n\n`handle` (#1213) sets your public identity, `firstname.lastname`, 3–64 characters of lowercase letters, digits, dots and dashes, starting and ending with a letter or digit. Unlike the preferences above, a bad handle is a **400**, not a silent no-op — taken, reserved and malformed each return a distinguishable message, because a person who chose a name needs to know it did not apply. There is no alias: changing your handle frees the old one immediately and it stops resolving. Changes are rate-limited to 5 per day per account; exceeding that is a 429.\n\n`linkedinUrl`, `githubUrl`, `websiteUrl`, `headline` and `bio` (#1214) are the profile content fields. URLs must be `https://` with a host — `http://`, `javascript:`, `data:` and host-less values are each a **400**; the value is normalised by trimming whitespace and dropping one trailing slash, and is otherwise stored as typed. `headline` is capped at 160 characters and `bio` at 500, and exceeding either is a 400 naming the field. Sending any of the five as `null` or an empty string clears it.\n\nEvery field that can be refused is validated before any field is written, so a rejected patch changes nothing at all.\n\n`standardChannel` sets which edition of the ODCS/ODPS standards artifacts created in your **personal** workspace declare. `Experimental` follows the newest bundled edition, which may be an unapproved DRAFT standard subject to change before TSC approval. It does **not** affect artifacts created in an organization's workspace — an org's own channel governs there. An unrecognised value is a 400, never coerced.","operationId":"patchProfile","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated UserResponse","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"400":{"description":"Unknown standardChannel value, or a malformed / reserved / already-taken handle","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"Too many handle changes (#1213)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.profile.update","description":"Update the authenticated user's preferences"}],"x-since":"7.6.0"}},"/v4/signing/auto-sign":{"patch":{"tags":["Signing"],"summary":"Toggle auto-sign setting","description":"**Since v4.5.0** — Enables or disables automatic signing before GitHub publish. Without ?org=, toggles the user's personal setting. With ?org=, toggles the organization's setting (requires ADMIN+ role).","operationId":"toggleAutoSign","parameters":[{"name":"enabled","in":"query","required":true,"schema":{"type":"boolean"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Auto-sign setting updated","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signing-key.auto-sign.update","description":"Toggle the auto-sign setting"}],"x-since":"4.5.0"}},"/v4/orgs/settings/standard-channel":{"get":{"tags":["Organization Settings"],"summary":"Get organization standard-version channel","description":"**Since v8.33.0** — Returns the organization's standard-version channel and, crucially, what it currently resolves to: `Production` alone does not tell an admin which ODCS/ODPS version new artifacts will declare. `Experimental` follows the newest bundled edition, which may be an unapproved DRAFT standard subject to change before TSC approval.\n\nThe channel is a standing intent, not a pinned version: when the TSC approves a draft, `Production` workspaces follow automatically with no migration.\n\nRequires org membership.","operationId":"getStandardChannel","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Channel plus its current resolution","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.standard-channel.get","description":"Get the organization's standard-version channel"}],"x-since":"8.33.0"},"patch":{"tags":["Organization Settings"],"summary":"Set organization standard-version channel","description":"**Since v8.33.0** — Sets the organization's standard-version channel to `Production` (the approved approved release), `Previous` (the newest approved release older than it) or `Experimental` (the newest bundled edition, which MAY be an unapproved DRAFT standard). Requires ADMIN+ role — this is a governance decision, not a member preference.\n\nChanging the channel affects only artifacts created afterwards. Existing artifacts are never rewritten or re-validated.\n\nAn unrecognised value is a 400; it is never coerced to a default, so a typo cannot quietly put an organization on draft standards.","operationId":"updateStandardChannel","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated channel plus its current resolution","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId, or an unknown channel value","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.settings.standard-channel.update","description":"Set the organization's standard-version channel"}],"x-since":"8.33.0"}},"/v4/admin/platform/features":{"patch":{"tags":["Administration"],"summary":"Set a global feature flag","description":"**Since v8.16.12** — Upsert one global feature flag. Body: {\"key\": \"<catalog key>\", \"enabled\": true|false}. An unknown key returns 400. platform-admin only.","operationId":"setFeature","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated flag (effective state)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing key/enabled or unknown feature key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"platform.setFeature","description":"Turn a global feature flag on or off for all users"}],"x-since":"8.16.12"}},"/v4/admin/orgs/{slug}":{"patch":{"tags":["Administration"],"summary":"Set organization feature flags (v4 admin)","description":"**Since v8.7.0** — Enables or disables per-org feature flags — conversational agent support (#984) and/or the Governance Coach (svc#983). Only the keys present in the request body are changed. When agent support is disabled the org's agent-provider endpoints return 403; when the coach is disabled the webapp editor hides the coach overlay. Admin only.","operationId":"setOrgFlags","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated organization object","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.org.flags","description":"Enable/disable per-org feature flags (agent support, governance coach)"}],"x-since":"8.7.0"}},"/v4/admin/orgs/{slug}/features":{"get":{"tags":["Administration"],"summary":"Per-org features","description":"**Since v8.16.13** — The feature catalog for one organization: each entry has the raw per-org value (orgEnabled), the global flag (globalEnabled), and effective (orgEnabled OR globalEnabled). Also carries `standardChannel` — the org's standard-version channel exactly as stored (#1451).","operationId":"features","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Per-org feature list","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.org.features","description":"Per-org feature catalog with raw/global/effective state"}],"x-since":"8.16.13"},"patch":{"tags":["Administration"],"summary":"Set a per-org feature","description":"**Since v8.16.13** — Upsert one per-org feature. Body: {\"key\": \"<catalog key>\", \"enabled\": true|false}. Unknown key returns 400, and so does a global-only feature (globalOnly=true in the catalog), which is set under Platform features instead. platform-admin only.","operationId":"setFeature_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated per-org feature list","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing key/enabled, unknown feature key, or a global-only feature that cannot be set per organization","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.org.setFeature","description":"Turn a feature on/off for one organization"}],"x-since":"8.16.13"}},"/v4/admin/invitation-codes/{id}":{"delete":{"tags":["Administration"],"summary":"Delete an admin invitation code","description":"**Since v7.13.0** — Only allowed when uses_count = 0. To deactivate a used code, revoke instead.","operationId":"delete_14","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"Deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Code has been used; revoke instead","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.delete","description":"Delete an unused admin invitation code"}],"x-since":"7.13.0"},"patch":{"tags":["Administration"],"summary":"Update or revoke an admin invitation code","description":"**Since v7.13.0** — Update label, expires_at, or revoke (revoke=true sets expires_at to now).","operationId":"update_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated code","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Bad request","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.update","description":"Update an admin invitation code"},{"name":"invitation-code.revoke","description":"Revoke an admin invitation code"}],"x-since":"7.13.0"}},"/v3/products/remove-contract":{"patch":{"tags":["Products"],"summary":"Remove a contract reference from a product (v3)","description":"**Since v3.4.0** — Removes a contract from the product's outputPorts without deleting the product. Used during safe deletion to detach a contract from referencing products.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeContract","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract reference removed successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or contract reference not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.contract.remove","description":"Remove a contract reference from a product"}],"x-since":"3.4.0","x-sunset":"2027-01-01"}},"/v2/users/profile":{"get":{"tags":["Users"],"summary":"Get user profile (v2)","description":"**Since v2.2.0** — Returns the authenticated user's profile. User is identified from JWT — no email param needed.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getProfile_1","responses":{"200":{"description":"UserResponse with profile details","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.profile.get","description":"Get the authenticated user's profile"}],"x-since":"2.2.0","x-sunset":"2027-01-01"},"patch":{"tags":["Users"],"summary":"Patch user preferences (v2)","description":"**Since v2.7.0** — Partial-update the authenticated user's profile preferences. Supports `inviteDigestOptOut: boolean` (#297) and the public-profile visibility flags `publicProfile: boolean` / `publicCompany: boolean` (#1212), and the profile content fields `linkedinUrl` / `githubUrl` / `websiteUrl` / `headline` / `bio` (#1214). URLs must be `https://` with a host and the two texts are capped at 160 and 500 characters; a bad value there is a 400, unlike the booleans, which ignore a non-boolean. `handle` is v4-only. Other fields are ignored.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"patchProfile_1","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated UserResponse","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.profile.update","description":"Update the authenticated user's preferences"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/admin/invitation-codes/{id}":{"delete":{"tags":["Administration"],"summary":"Delete an admin invitation code","description":"**Since v2.7.0** — Only allowed when uses_count = 0. To deactivate a used code, revoke instead.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"delete_15","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"Deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Code has been used; revoke instead","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.delete","description":"Delete an unused admin invitation code"}],"x-since":"2.7.0","x-sunset":"2027-01-01"},"patch":{"tags":["Administration"],"summary":"Update or revoke an admin invitation code","description":"**Since v2.7.0** — Update label, expires_at, or revoke (revoke=true sets expires_at to now).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"update_4","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Updated code","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Bad request","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-code.update","description":"Update an admin invitation code"},{"name":"invitation-code.revoke","description":"Revoke an admin invitation code"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v4/users/{handle}/public":{"get":{"tags":["Public Profiles"],"summary":"Get a user's public profile","description":"**Since v9.38.0** — Returns the public profile behind a handle, as a signed-in Workbench user is entitled to see it.\n\n**Requires a JWT.** \"Public\" means visible to signed-in platform users, not to the open internet, and there is deliberately no endpoint that lists or searches profiles — you can only read one whose handle you already know.\n\n**A profile that is not public returns 404, not 403, with a body byte-identical to an unknown handle.** A 403 would confirm the account exists. The same 404 covers an account whose owner has not opted in, an end-to-end test account (excluded at read time from the address itself, whatever the stored flag says), and a handle nobody holds.\n\nNo field in this response is or contains an email address. `gravatarHash` is the hex SHA-256 of the subject's lowercased, trimmed account email: anyone already holding that address can confirm a match against it, which is inherent to Gravatar and is why it is emitted only for a profile its owner has made public.\n\n`company` is present only when the subject has left `publicCompany` on. `organizations[]` lists only those organizations that may be named publicly, and is never a member list. `rank` is scoped to an organization the viewer shares with the subject and is absent when they share none — or more than one, where there is no basis to choose. It is never a global rank.","operationId":"getPublicProfile","parameters":[{"name":"handle","in":"path","description":"The subject's public handle, e.g. `jean-georges.perrin`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The public profile","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PublicProfileResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such handle, or the profile is not public — the two are indistinguishable by design","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.profile.public.get","description":"Read another user's public profile by handle"}],"x-since":"9.38.0"}},"/v4/users/search":{"get":{"tags":["Users"],"summary":"Search users (org-invite autocomplete)","description":"**Since v7.22.0** — Case-insensitive substring match on first name, last name, and email, restricted to the invite pool: users whose email domain matches the caller's, plus users sharing at least one organization with the caller (#679). Queries shorter than 3 characters return an empty list; results are capped at 20. Never exposes admin-only fields (#599).","operationId":"search","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of UserSearchResponse","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.search","description":"Search users for org-invite autocomplete"}],"x-since":"7.22.0"}},"/v4/users/me/messages":{"get":{"tags":["Notifications"],"summary":"List my messages","description":"**Since v9.82.0** — Returns every message a platform admin sent the caller, newest first, with the sender resolved to a name and email, and the number still unread.","operationId":"list_9","responses":{"200":{"description":"{ messages: [UserMessageResponse...], unreadCount: n }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.message.list","description":"List the caller's messages from platform admins"}],"x-since":"9.82.0"}},"/v4/users/me/linked-identities":{"get":{"tags":["Users"],"summary":"Linked identity providers for the calling account","description":"**Since v9.67.0** — Reports whether the caller has a linked GitHub identity and which login it is, so a profile page can show a Connected accounts section and render a **verified** GitHub link differently from a hand-typed one.\n\nReports on the **caller** only — there is no user parameter, so this cannot be used to learn whether another account has linked GitHub.\n\nA caller with no link gets a well-formed `linked: false` answer, never a 404.\n\nRead-only: there is no unlink or revoke operation.","operationId":"linkedIdentities","responses":{"200":{"description":"The caller's linked identities","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LinkedIdentitiesResponse"}}}},"401":{"description":"Missing or invalid credentials","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LinkedIdentitiesResponse"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"user.linked-identities.get","description":"The calling account's linked identity providers"}],"x-since":"9.67.0"}},"/v4/users/me/integrations":{"get":{"tags":["Publishing"],"summary":"Get all integration statuses","description":"**Since v7.6.0** — Returns a summary of which integrations are configured for the authenticated user.","operationId":"getAllStatuses","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.list","description":"List all integration statuses"}],"x-since":"7.6.0"}},"/v4/users/me/integrations/{key}/status":{"get":{"tags":["Publishing"],"summary":"Get integration status","description":"**Since v7.6.0** — Returns non-secret config, configured boolean, and last test result for the specified integration.","operationId":"getStatus","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.get","description":"Get a single integration status"}],"x-since":"7.6.0"}},"/v4/templates":{"get":{"tags":["Templates"],"summary":"List the catalog of pre-built ODCS contract templates","description":"**Since v7.0.66** — Returns the global catalog of starter ODCS contract templates the Workbench Template Gallery offers when a user creates a new contract. Each item carries the raw ODCS YAML body the webapp clones as the seed for the new contract, plus the apiVersion that body declares and that version's status (draft/approved/deprecated). The starter templates are on the approved release; a template whose status is 'draft' showcases an edition of the standard the TSC has not approved yet and should be labelled as such in the gallery (#1088).","operationId":"listTemplates","responses":{"200":{"description":"{ items: TemplateDto[], total: int }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT bearer token","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"templates.list","description":"List pre-built ODCS contract templates"}],"x-since":"7.0.66"}},"/v4/tags":{"get":{"tags":["Tags"],"summary":"List tags with counts (v4)","description":"**Since v7.0.9** — Returns the flat list of tags with the count of artifacts that use each one. Counts mirror the per-tag artifact list returned by /v4/tags/cloud.","operationId":"listTags_3","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ items: [{name, count}] }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"reference-tag.list","description":"List tags with artifact counts"}],"x-since":"7.0.9"}},"/v4/tags/cloud":{"get":{"tags":["Tags"],"summary":"Get tag cloud (v4)","description":"**Since v7.0.9** — Returns all tags across the caller's (or an organization's) contracts and products, with the artifacts that use each tag. Reference-tag usages appear as `$ref:`-prefixed keys.","operationId":"getTagCloud","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ tags: { tagName: [{id, version, name, type}] } }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"tag-cloud.get","description":"Get the org-aware tag cloud"}],"x-since":"7.0.9"}},"/v4/products/{productId}":{"get":{"tags":["Products"],"summary":"Get a data product","description":"**Since v7.13.3** — Retrieves a data product by ID. Pass org or orgId for organization products.\n\n| Format | Content-Type | Description |\n|--------|--------------|-------------|\n| _(none)_ / `FULL` | `application/x-yaml` | The raw ODPS YAML |\n| `PrettyPDF` | `application/pdf` | Branded PDF with the workspace logo and PDF settings |\n| `DDL` | `text/plain` or `application/zip` | SQL DDL for every contract on the product's ports (#1047) |\n\nAn unrecognized format returns the ODPS YAML.\n\n**format=DDL** requires `subformat` (the SQL dialect). A product with exactly one referenced contract returns the bare `.sql`; two or more return a ZIP holding `input/`, `output/`, `src/` (the original ODPS + ODCS) and a `MANIFEST.md`. Pass `zip=true` to always get a ZIP.","operationId":"read","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","description":"Response format — PrettyPDF renders the branded product PDF (svc#941); DDL exports the product's contracts as SQL (#1047)","required":false,"schema":{"type":"string","enum":["FULL","PrettyPDF","DDL"]}},{"name":"subformat","in":"query","description":"SQL dialect. Required when format=DDL. Call GET /v4/ddl/dialects for the current list.","required":false,"schema":{"type":"string"}},{"name":"zip","in":"query","description":"With format=DDL, force a ZIP even when the product has a single contract","required":false,"schema":{"type":"boolean","default":false}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product in the requested format","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"format=DDL with a missing or unsupported subformat","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"PDF or DDL generation failed","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.get","description":"Retrieve a data product by ID"}],"x-since":"7.13.3"},"delete":{"tags":["Products"],"summary":"Delete a product (path form)","description":"**Since v9.94.1** — Identical to `DELETE /v4/products?productId=…&version=…` and delegates to the same handler. Added alongside the contract equivalent (#1434): both previously answered 500 from the wrong-method catch-all, because `GET /v4/products/{productId}` exists and the matching DELETE did not.\n\n`version` is required, for the same reason as on contracts.","operationId":"deleteByPath","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product deleted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"version was not supplied","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product, version or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete","description":"Delete a data product"}],"x-since":"9.94.1"}},"/v4/products/{productId}/verify-signature":{"get":{"tags":["Verification"],"summary":"Verify signature on a stored product (public)","description":"**Since v7.31.0** — Verifies the digital signature embedded in the specified product, resolved by id across all storage. No authentication required — product ids are unguessable UUIDs. Omit version for the latest.","operationId":"verifyProduct","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification result","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"signature.verify","description":"Verify signature on a stored product"}],"x-since":"7.31.0"}},"/v4/products/{productId}/attachments/{name}":{"get":{"tags":["V4 - Product attachments"],"summary":"Download one attachment's bytes","description":"**Since v9.99.1** — Streams the stored bytes with the `mimeType` recorded on the entry.\n\n**The document is authoritative, not the directory.** The attachment is looked up in `customProperties` first, so a file sitting in the product's directory with no entry is a 404 here — the persisted document is what publishes and what a consumer sees, and trusting the filesystem instead would make an orphaned file downloadable.\n\nAn **external** entry (absolute `http(s)` url, no `#` prefix) is refused with a message naming the reason. svc does not fetch the remote on your behalf — that would turn this endpoint into an arbitrary outbound fetcher pointed by data a user controls.","operationId":"download","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The file's bytes","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"The entry is an external link, or its bytes are missing from the store","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not permitted for this product","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such attachment on this product","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"product.attachment.download","description":"Download an attached file"}],"x-since":"9.99.1"},"delete":{"tags":["V4 - Product attachments"],"summary":"Remove an attachment from a data product","description":"**Since v9.99.1** — Removes the `customProperties` entry **and**, for an internal attachment, the stored file.\n\nAn **external** entry removes the entry and touches no file — there is nothing of ours to delete.\n\nA second delete of the same name is a clean **404**, not an error: the caller asked for a state that already holds.","operationId":"delete_16","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not permitted for this product","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such attachment on this product","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"product.attachment.delete","description":"Remove an attached file"}],"x-since":"9.99.1"}},"/v4/products/maturity-level":{"get":{"tags":["Products"],"summary":"Measure product maturity level (OMMS v0.2.0)","description":"**Since v4.2.0** — Returns a maturity level (0-5) for the specified data product using the OMMS v0.2.0 maturity model for ODPS. Includes policy evaluation results and level caps. Pass org or orgId for organization products.","operationId":"getMaturityLevel","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Maturity assessment result with policy results","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.maturity","description":"Measure data product maturity level"}],"x-since":"4.2.0"}},"/v4/products/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get product lifecycle history (v4, born-deprecated)","description":"**Since v7.1.6** — Verbatim copy of GET /v1/products/lifecycle.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getProductLifecycle","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.product.list","description":"Get product lifecycle history"}],"x-since":"7.1.6","x-sunset":"2027-01-01"}},"/v4/products/delete-check":{"get":{"tags":["Products"],"summary":"Pre-delete dependency check","description":"**Since v7.13.3** — Returns prior versions and referenced contracts for a product, so the client can show a comprehensive delete confirmation modal. Read-only — no mutation.","operationId":"deleteCheck","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delete check result with prior versions and referenced contracts","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete-check","description":"Check product dependencies before delete"}],"x-since":"7.13.3"}},"/v4/products/ddl":{"get":{"tags":["Products"],"summary":"Download data product DDL","description":"**Since v8.22.0** — Generates SQL DDL from the data contracts on each product's input and output ports and returns them as one ZIP (#1047).\n\nThe archive holds `input/` and `output/` folders — a contract used as both is emitted under each — plus `src/` with the original ODPS and ODCS documents verbatim, and a `MANIFEST.md` listing every file with its role. Each `.sql` opens with a banner naming the product, port, role and contract.\n\nA plain GET so a browser can download it directly. At most 50 products per request. Contracts that cannot be resolved in the workspace are reported in the manifest rather than failing the download; an unreadable **product** is a 404 naming the id.","operationId":"ddl","parameters":[{"name":"productId","in":"query","description":"Data product id; repeat the parameter for several products (max 50)","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"version","in":"query","description":"Version of the product, when a single one is requested. Latest by default.","required":false,"schema":{"type":"string"}},{"name":"subformat","in":"query","description":"SQL dialect. Call GET /v4/ddl/dialects for the current list.","required":false,"schema":{"type":"string","default":"PostgreSQL"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"ZIP archive of generated DDL","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No productId, more than 50, or a missing/unsupported subformat","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"A requested data product was not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.ddl","description":"Download SQL DDL for one or more data products"}],"x-since":"8.22.0"}},"/v4/products/compare":{"get":{"tags":["Products"],"summary":"Compare two data products","description":"**Since v9.32.0** — Compares two data products and returns a DiffResult with the differences, their semver impact levels and a suggested next version. Port semantics are svc's documented vendor default pending upstream ratification — see ProductComparator. Pass org or orgId to compare organization products.","operationId":"compareProducts","parameters":[{"name":"id1","in":"query","required":true,"schema":{"type":"string"}},{"name":"version1","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage1","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"id2","in":"query","required":true,"schema":{"type":"string"}},{"name":"version2","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage2","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"all"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"DiffResult JSON with differences and suggested version","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or a product or version not found on either side of the compare","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Comparison failure","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.compare","description":"Compare two data products"}],"x-since":"9.32.0"}},"/v4/presence/{kind}/{id}":{"get":{"tags":["Presence"],"summary":"Active viewers of an artifact","description":"**Since v7.24.0** — Returns the users currently viewing the artifact and registers/refreshes the caller as a viewer (the poll IS the heartbeat). Viewers with no poll within 60 seconds disappear. kind is 'contract' or 'product'.","operationId":"getPresence","parameters":[{"name":"kind","in":"path","description":"Artifact kind, in either vocabulary: contract, product, DataContract or DataProduct. 'App' has no presence surface.","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"Artifact id (same key space as /v4/artifacts)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PresenceResponse with the active viewers","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid kind","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"presence.get","description":"List active viewers of an artifact (and register the caller)"}],"x-since":"7.24.0"}},"/v4/podemites/transactions":{"get":{"tags":["Podemites"],"summary":"List Podemite awards","description":"**Since v9.53.0** — The authenticated user's Podemite ledger, newest first. Each row carries a `source`: CONSUMPTION (one per credit consumed), BONUS (granted by an admin) or BACKFILL (the one-time opening balance derived from credit history predating Podemites). Amounts are always positive.","operationId":"getTransactions","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Ledger returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"podemite.transactions.list","description":"List the caller's Podemite awards"}],"x-since":"9.53.0"}},"/v4/podemites/balance":{"get":{"tags":["Podemites"],"summary":"Get Podemite total","description":"**Since v9.53.0** — The authenticated user's lifetime Podemite total. Podemites only ever go up: one is earned for every credit consumed, plus any admin bonus grants. This is the quantity the leaderboard ranks on.","operationId":"getTotal","responses":{"200":{"description":"{ total: n }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"podemite.balance.get","description":"Get the caller's Podemite total"}],"x-since":"9.53.0"}},"/v4/platform/features":{"get":{"tags":["Platform"],"summary":"Global feature flags","description":"**Since v8.16.12** — The full catalog of global (all-users) feature flags with each flag's effective on/off state — the persisted value when an admin has set it, else the compiled default. Readable by any authenticated user (no org required) so the client can gate features for personal-context users too.","operationId":"features_1","responses":{"200":{"description":"Feature catalog with effective state","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"platform.features","description":"Global feature flags with their effective on/off state"}],"x-since":"8.16.12"}},"/v4/orgs/{slug}/public":{"get":{"tags":["Public Profiles"],"summary":"Get an organization's public page","description":"**Since v9.41.0** — Returns the organization's name, slug, a logo URL when it has one, and how many of its members have made their own profile public.\n\n**Requires a JWT**, like every other endpoint in this epic — \"public\" means visible to signed-in platform users, not to the open internet.\n\n**An organization that has turned `publicCompany` off returns 404, not 403, with a body byte-identical to an unknown slug.** A 403 would confirm it exists.\n\n`publicMemberCount` is a **count, never a list** — there is deliberately no endpoint that enumerates an organization's members. It counts only members who have opted in themselves: an organization opting in does not opt its people in, so an org of 40 where 3 are public reports 3.\n\n`publicCompany` is not `discoverable`. That one is domain-based auto-discovery at `/v2/orgs/discover` and is untouched by this endpoint.","operationId":"getPublicOrg","parameters":[{"name":"slug","in":"path","description":"The organization's slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The organization's public page","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PublicOrgResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such slug, or the organization is not publicly nameable — the two are indistinguishable by design","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.public.get","description":"Read an organization's public page"}],"x-since":"9.41.0"}},"/v4/orgs/{slug}/public/logo":{"get":{"tags":["Public Profiles"],"summary":"Get a public organization's logo","description":"**Since v9.41.0** — Serves the SVG logo referenced by `logoUrl` on the organization's public page. Gated identically to that page — a JWT, and the organization being publicly nameable — so a non-member can render the logo on a profile without being let into the organization's own settings. An organization that is not publicly nameable, one with no logo, and an unknown slug are all the same 404.","operationId":"getPublicOrgLogo","parameters":[{"name":"slug","in":"path","description":"The organization's slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The SVG logo","content":{"image/svg+xml":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"image/svg+xml":{"schema":{"type":"object"}}}},"404":{"description":"No such organization, not publicly nameable, or no logo — indistinguishable by design","content":{"image/svg+xml":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.public.logo","description":"Fetch a public organization's logo"}],"x-since":"9.41.0"}},"/v4/orgs/{slug}/products/{productId}":{"get":{"tags":["Organization Products"],"summary":"Get an organization product","description":"**Since v7.9.0** — Retrieves a product by ID from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"ODPS YAML content","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.get","description":"Retrieve a data product by ID"}],"x-since":"7.9.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/messages":{"get":{"tags":["Membership"],"summary":"List pending messages (deprecated slug path)","description":"**Since v7.11.0** — Admin/owner views pending join requests and invitations. Deprecated — use GET /v4/orgs/messages with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listPendingMessagesBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of pending messages","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/members":{"get":{"tags":["Membership"],"summary":"List organization members (deprecated slug path)","description":"**Since v7.11.0** — Returns all members of the organization. Requires membership. Deprecated — use GET /v4/orgs/members with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listMembersBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of members","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/integrations":{"get":{"tags":["Organization Settings"],"summary":"Get all org integration statuses (deprecated slug path)","description":"**Since v7.10.0** — Returns the status of every org integration. Requires org membership. Deprecated — use GET /v4/orgs/integrations with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getAllStatusesBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/integrations/{key}/status":{"get":{"tags":["Organization Settings"],"summary":"Get org integration status (deprecated slug path)","description":"**Since v7.10.0** — Returns the status of a single org integration. Requires org membership. Deprecated — use GET /v4/orgs/integrations/{key}/status with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getStatusBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.10.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/credits/usage":{"get":{"tags":["Credits"],"summary":"Get organization Credits usage","description":"**Since v7.44.0** — Returns daily Credits consumption totals for the specified organization over the last 30 days. Only the org creator can access this.","operationId":"getOrgUsageBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary returned (date → amount map)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not the organization creator","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.org.usage.get","description":"Get an organization's daily Credits usage summary"}],"x-since":"7.44.0"}},"/v4/orgs/{slug}/credits/transactions":{"get":{"tags":["Credits"],"summary":"Get organization Credits transactions","description":"**Since v7.44.0** — Returns the transaction history for the specified organization (paginated). Only the org creator can access this.","operationId":"getOrgTransactionsBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Org transaction list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not the organization creator","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.org.transaction.list","description":"List an organization's Credits transactions"}],"x-since":"7.44.0"}},"/v4/orgs/{slug}/credits/balance":{"get":{"tags":["Credits"],"summary":"Get organization Credits balance","description":"**Since v7.44.0** — Returns the Credits balance for the specified organization. Only the org creator can access this.","operationId":"getOrgBalanceBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Org balance returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not the organization creator","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.org.balance.get","description":"Get an organization's Credits balance"}],"x-since":"7.44.0"}},"/v4/orgs/{slug}/contracts/{contractId}":{"get":{"tags":["Organization Contracts"],"summary":"Get an organization contract","description":"**Since v7.8.0** — Retrieves a contract by ID in the specified format from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_2","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string"}},{"name":"subformat","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"Contract in requested format","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.get","description":"Get an organization contract"}],"x-since":"7.8.0","x-sunset":"2027-01-01"}},"/v4/orgs/service-accounts/scopes":{"get":{"tags":["Service Accounts"],"summary":"List the grantable service-account scopes","description":"**Since v7.54.0** — Returns every scope a service account may be granted, each with a domain, a short label, and a one-line description — the vocabulary a scope picker renders. Sourced from ServiceAccountService.ALLOWED_SCOPES so the API and any client picker can never disagree. Requires authentication only (not org-admin); the vocabulary is global and carries no secret material.","operationId":"scopes","responses":{"200":{"description":"Array of grantable scopes with domain/label/description","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"serviceaccount.scopes","description":"List grantable service-account scopes"}],"x-since":"7.54.0"}},"/v4/orgs/search":{"get":{"tags":["Organizations"],"summary":"Search organizations by name","description":"**Since v7.7.0** — Returns organizations whose name contains the query string (case-insensitive).","operationId":"search_1","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of matching organizations","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.search","description":"Search organizations by name"}],"x-since":"7.7.0"}},"/v4/orgs/plugins/{id}/disclosure":{"get":{"tags":["Organization Plugins"],"summary":"Plugin activation disclosure","description":"**Since v9.3.0** — What the org admin is shown before activating: the plugin's identity, every menu it extends, the payload scope of each, and the fixed statement that it receives the invoking member's name and email. Derived from the manifest. Requires ADMIN+ role.","operationId":"disclosure","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The disclosure","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or plugin not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.disclosure","description":"What a plugin declared, before activating it"}],"x-since":"9.3.0"}},"/v4/orgs/plugins/contributions":{"get":{"tags":["Organization Plugins"],"summary":"Effective plugin contributions","description":"**Since v9.3.0** — The flattened contributions of every plugin that is activated for the organization and not disabled by a platform admin — the surface the Workbench renders from. Never includes an endpoint, a token, or a settings value. Requires org membership.","operationId":"contributions","parameters":[{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of contributions","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.contributions","description":"The plugin contributions this member should see"}],"x-since":"9.3.0"}},"/v4/orgs/mine":{"get":{"tags":["Organizations"],"summary":"List my organizations","description":"**Since v7.7.0** — Returns all organizations the authenticated user belongs to, with their role in each.","operationId":"getMyOrgs","responses":{"200":{"description":"List of organizations with membership role","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.list","description":"List organizations the caller belongs to"}],"x-since":"7.7.0"}},"/v4/orgs/messages":{"get":{"tags":["Membership"],"summary":"List pending messages","description":"**Since v7.26.0** — Admin/owner views pending join requests and invitations. Pass org (slug) or orgId (UUID) to select the organization. Requires ADMIN+ role.","operationId":"listPendingMessages","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of pending messages","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.message.list","description":"List pending join requests and invitations"}],"x-since":"7.26.0"}},"/v4/orgs/members":{"get":{"tags":["Membership"],"summary":"List organization members","description":"**Since v7.26.0** — Returns all members of the organization. Pass org (slug) or orgId (UUID) to select the organization. Requires membership — except platform-admins, who may read any org's members (the admin \"Manage org\" panel, #772).","operationId":"listMembers","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of members","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.list","description":"List organization members"}],"x-since":"7.26.0"}},"/v4/orgs/invitations/mine":{"get":{"tags":["Membership"],"summary":"List my pending organization invitations","description":"**Since v7.43.40** — Returns the pending organization invitations addressed to the authenticated user, newest first. Self-scoped: reachable by any authenticated user (not org-scoped, not admin-gated). Each row carries the org slug/name, inviter, and a messageId usable with PUT /v4/orgs/messages/{messageId}/accept|decline. Invitations to orgs the caller already belongs to are excluded.","operationId":"myInvitations","responses":{"200":{"description":"The caller's pending invitations (possibly empty)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.invitation.list-mine","description":"List the caller's own pending org invitations"}],"x-since":"7.43.40"}},"/v4/orgs/integrations":{"get":{"tags":["Organization Settings"],"summary":"Get all org integration statuses","description":"**Since v7.26.0** — Returns the status of every org integration. Pass org (slug) or orgId (UUID) to select the organization. Requires org membership.","operationId":"getAllStatuses_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Integration statuses","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.list","description":"List all org integration statuses"}],"x-since":"7.26.0"}},"/v4/orgs/integrations/{key}/status":{"get":{"tags":["Organization Settings"],"summary":"Get org integration status","description":"**Since v7.26.0** — Returns the status of a single org integration. Pass org (slug) or orgId (UUID) to select the organization. Requires org membership.","operationId":"getStatus_1","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Integration status","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or unknown integration key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.get","description":"Get a single org integration status"}],"x-since":"7.26.0"}},"/v4/orgs/discover":{"get":{"tags":["Organizations"],"summary":"Discover organization by email","description":"**Since v7.7.0** — Finds the organization whose domain matches the given email address.","operationId":"discover","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization found (or empty if no match)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.discover","description":"Find an organization by email domain"}],"x-since":"7.7.0"}},"/v4/orgs/agents":{"get":{"tags":["Organization Agent Providers"],"summary":"List imported agents","description":"**Since v8.6.0** — Returns the agents imported from the organization's enabled providers (de-duplicated). Pass org (slug) or orgId (UUID). Requires org membership.","operationId":"agents","parameters":[{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of agent cards","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.agents.list","description":"List the organization's imported agents"}],"x-since":"8.6.0"}},"/v4/notifications":{"get":{"tags":["Notifications"],"summary":"List notifications","description":"**Since v7.23.0** — Returns the caller's notification feed — open task assignments, unresolved threads they authored or are @mentioned in, and (for platform admins only) pending signup requests, and the caller's unread messages from platform admins, newest first, with an unread count relative to the mark-all-read watermark. Entry types are 'task', 'thread', 'signup_request' and 'message'. Derived live from the underlying records; there is no notification table, and nothing is dismissed: a signup_request entry disappears when the request stops being pending, a message entry once POST /v4/users/me/messages/{id}/read stamps it. Requests from the Playwright E2E accounts never produce a notification.","operationId":"list_10","responses":{"200":{"description":"{ notifications: [...], unreadCount: n }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"notifications.list","description":"List the caller's notifications with unread count"}],"x-since":"7.23.0"}},"/v4/notifications/announcements":{"get":{"tags":["Notifications"],"summary":"Every platform announcement ever sent (admin)","description":"**Since v9.103.0** — #1471 AC-7 — what the platform has sent, and when. Admin-only. Each row carries the audience it was addressed to, which is the scoped set of users the triggering action actually wrote to: a user who was skipped is deliberately not in it, because telling somebody their demos were updated when their edits were preserved reads as \"my work was overwritten\".","operationId":"listAnnouncements","responses":{"200":{"description":"Newest first","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid credentials","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not an admin","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"announcement.list","description":"Read back every platform announcement"}],"x-since":"9.103.0"}},"/v4/me":{"get":{"tags":["Users"],"summary":"Get the authenticated user","description":"**Since v7.0.41** — Returns the current user's profile, resolved from the bearer JWT. Includes a UI-ready displayName that is never a raw UUID.","operationId":"me","responses":{"200":{"description":"The authenticated user","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"me.get","description":"Get the authenticated user's profile"}],"x-since":"7.0.41"}},"/v4/me/api-key":{"get":{"tags":["Users"],"summary":"Get the caller's API key","description":"**Since v7.0.59** — Returns the authenticated caller's API key, resolved from the bearer JWT — no email or password is needed, so this works for accounts created via the OAuth 2.1 sign-in flow, which have no password the caller knows. The returned key is used in the X-API-KEY header for API-key-authenticated endpoints.","operationId":"apiKey","responses":{"200":{"description":"ApiKeyResponse containing the caller's API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"me.api-key.get","description":"Get the caller's API key"}],"x-since":"7.0.59"}},"/v4/maturity-model":{"get":{"tags":["Maturity Model"],"summary":"Get a maturity-model definition","description":"**Since v7.43.5** — Returns the maturity model (metadata + levels[], each with its criteria[]) for the given kind (contract or product). Read-only reference data. Served from the caller's provisioned copy when present, falling back to the bundled default.","operationId":"getMaturityModel","parameters":[{"name":"kind","in":"query","description":"Which model to return: 'contract' (default) or 'product'","required":false,"schema":{"type":"string","default":"contract"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The maturity-model definition as JSON","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown kind (must be 'contract' or 'product')","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid credentials","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"The maturity model could not be read","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.model.get","description":"Get the maturity-model definition for contracts or products"}],"x-since":"7.43.5"}},"/v4/maturity-history":{"get":{"tags":["Maturity History"],"summary":"Get maturity history","description":"**Since v7.2.0** — Returns daily maturity level distribution snapshots for contracts or products. Pass org or orgId for org-scoped data; omit for personal data. Defaults to the last 90 days if from/to are omitted.\n\n`artifactType` accepts either vocabulary, case-insensitively: `contract` / `DataContract` and `product` / `DataProduct` (#1474). `App` is recognised vocabulary but has no maturity snapshots, so it is rejected with 400.","operationId":"getMaturityHistory","parameters":[{"name":"artifactType","in":"query","description":"Artifact type: 'contract' / 'DataContract' or 'product' / 'DataProduct' (either spelling, case-insensitive)","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start date (yyyy-MM-dd), defaults to 90 days ago","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"End date (yyyy-MM-dd), defaults to today","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of {date, maturityLevel, count} objects","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid artifactType or date format","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.history.get","description":"Get maturity distribution history"}],"x-since":"7.2.0"}},"/v4/logs":{"get":{"tags":["Users"],"summary":"Get the caller's activity log","description":"**Since v7.43.37** — Returns the authenticated caller's own ActivityLog entries, newest first, resolved from the bearer JWT. Self-scoped: a user only ever sees their own log — cross-user and admin filtering lives on /v4/admin/logs. Use 'limit' to bound the count (default 20, capped at 200).","operationId":"myLogs","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}}],"responses":{"200":{"description":"The caller's activity log entries, newest first","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActivityLog"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActivityLog"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"me.logs.get","description":"Get the authenticated user's own activity log"}],"x-since":"7.43.37"}},"/v4/leaderboard":{"get":{"tags":["Badges"],"summary":"Ranked standings","description":"**Since v9.14.0** — Ranks users by Credits **earned** in the period — the sum of positive `credit_transaction` rows, not `user_credit_balance`, which falls when a user spends credits and would therefore rank the heaviest users of the product lowest. Ranks are dense and 1-based; users on equal points share a rank and order deterministically by user id, so nobody swaps places between refreshes. `scope` defaults to `org` and ranks within one organization (pass `?org={slug}`); `scope=global` ranks across all tenants and is open to any authenticated caller (#1540). It does not leak across customer boundaries, because the global board is the only one that anonymises — see below. `limit` defaults to 50 and clamps to 100 so the endpoint cannot enumerate the platform. An unknown `period` is a 400, never a silent fallback.\n\n**Everyone ranked is returned; users who have not made their profile public are returned anonymised** (#1228, replacing #1216's filter). Their row keeps its real rank and points, carries `anonymized: true`, and its `displayName` is **already masked in this response** — `J***-G****** P*****`. Masking is done on the server, so the real name of a user who has not opted in is not in the payload at all; a client does not apply the format, it renders what it is given. Opting in changes from *appear at all* to *appear under your real name*.\n\nThis is a deliberate reversal of #1216, which hid non-public users entirely: #1212 left `publicProfile` NULL on every pre-existing account, so the filter emptied the board for everybody. An anonymised row does reveal that an account exists, its score and its rank — that trade was made knowingly in favour of a leaderboard people can actually read.\n\n**End-to-end test accounts are excluded outright**, decided on the address at read time rather than from a column, and the list is re-densified after that removal so ranks stay contiguous. Everything happens on read, so flipping `publicProfile` changes the next response with no snapshot recomputation, and a masked user keeps earning credits and badges exactly as before — they can still win Top Dog. `scope=global` behaves identically.\n\n**The caller always sees their own row** under their **real** name, whatever their setting, carrying `self: true` and `anonymized: false`. Identify it with `self`, never by display-name equality — a masked row cannot equal your real name and two masked users can collide.","operationId":"standings","parameters":[{"name":"period","in":"query","description":"all | week | month | year","required":false,"schema":{"type":"string","default":"all"}},{"name":"scope","in":"query","description":"org (default) | global — global ranks across all tenants, anonymised","required":false,"schema":{"type":"string","default":"org"}},{"name":"org","in":"query","description":"Organization slug, required for `scope=org`","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size; defaults to 50, clamped to 100","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Ranked standings, possibly empty","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LeaderboardEntry"}}}}},"400":{"description":"Bad `period`, or `scope=org` with no org","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"An org the caller is not a member of","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"leaderboard.list","description":"Ranked standings for a period"}],"x-since":"9.14.0"}},"/v4/health":{"get":{"tags":["Administration"],"summary":"Health check (v4)","description":"**Since v7.0.68** — Returns service version info and status for any authenticated caller. Admin users additionally see extended diagnostics (deployment time, database availability, environment variables, classpath packages). Body shape matches GET /v1/health (#569).","operationId":"getHealth","responses":{"200":{"description":"JSON with version info (all callers) and extended diagnostics (admins).","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid Bearer JWT.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"health.get","description":"Service health and version info"}],"x-since":"7.0.68"}},"/v4/github/verify-access":{"get":{"tags":["Automation"],"summary":"Verify repository access (v4, born-deprecated)","description":"**Since v7.1.2** — Verifies that the GitHub token has sufficient permissions to access and modify the repository. Supports org context (?org=/?orgId=) and integration-default repoUrl resolution; v3-aligned behavior (#640).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"verifyAccess","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Access verification result","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.verify-access","description":"Verify GitHub repository access"}],"x-since":"7.1.2","x-sunset":"2027-01-01"}},"/v4/github/actions/runs":{"get":{"tags":["Automation"],"summary":"Get latest workflow run (v4, born-deprecated)","description":"**Since v7.1.2** — Returns the status of the latest workflow run. Org context and integration-default resolution; v3-aligned (#640).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getLatestRun","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Latest workflow run status","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.run.get","description":"Get the latest workflow run"}],"x-since":"7.1.2","x-sunset":"2027-01-01"}},"/v4/diagnostics/{id}/steps/{seq}/image":{"get":{"tags":["Diagnostics"],"summary":"Stream a story step's screenshot (admin only)","description":"**Since v7.34.10**","operationId":"stepImage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"seq","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image bytes","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid Bearer JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No screenshot for this step","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"diagnostics.step.image","description":"Stream a step's screenshot"}],"x-since":"7.34.10"}},"/v4/ddl/dialects":{"get":{"tags":["DDL"],"summary":"List supported SQL dialects","description":"**Since v8.22.0** — Returns every SQL dialect the DDL generator knows about, in display order. `id` is the value to pass as `subformat` to the DDL endpoints; `available` is false for dialects that are on the roadmap but not implemented — those are advertised so clients can show them as coming soon, and rejected with 400 if actually requested.","operationId":"listDialects","responses":{"200":{"description":"{ items: [{ id, label, available }], total: int, default: string }","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT bearer token","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"ddl.dialects.list","description":"List the SQL dialects DDL export can target"}],"x-since":"8.22.0"}},"/v4/data-sources":{"get":{"tags":["Data Sources"],"summary":"List reusable named data sources","description":"**Since v7.35.0** — Returns every named data source in the caller's scope (personal, or the org when org/orgId is supplied). Passwords are never included.","operationId":"list_11","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Data sources (no secret material)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"datasource.list","description":"List reusable named data sources"}],"x-since":"7.35.0"}},"/v4/credits/usage":{"get":{"tags":["Credits"],"summary":"Get Credits usage summary","description":"**Since v7.44.0** — Returns a daily usage breakdown for the last 30 days.","operationId":"getUsageSummary","responses":{"200":{"description":"Usage summary returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.usage.get","description":"Get the user's daily Credits usage summary"}],"x-since":"7.44.0"}},"/v4/credits/transactions":{"get":{"tags":["Credits"],"summary":"Get Credits transactions","description":"**Since v7.44.0** — Returns the authenticated user's transaction history (paginated).","operationId":"getTransactions_1","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Transaction list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.transaction.list","description":"List the user's Credits transactions"}],"x-since":"7.44.0"}},"/v4/credits/org-balances":{"get":{"tags":["Credits"],"summary":"Get all organization Credits balances (admin)","description":"**Since v7.44.0** — Returns aggregate Credits balances for every organization. Admin only.","operationId":"getAllOrgBalances","responses":{"200":{"description":"Org balance list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.org-balance.list","description":"List Credits balances for all orgs (admin)"}],"x-since":"7.44.0"}},"/v4/credits/balance":{"get":{"tags":["Credits"],"summary":"Get Credits balance","description":"**Since v7.44.0** — Returns the authenticated user's current Credits balance.","operationId":"getBalance","responses":{"200":{"description":"Balance returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.balance.get","description":"Get the user's Credits balance"}],"x-since":"7.44.0"}},"/v4/contracts/{contractId}":{"get":{"tags":["Contracts"],"summary":"Get a data contract","description":"**Since v7.13.4** — Retrieves a contract by ID in the specified format. Pass org or orgId for organization contracts.","operationId":"read_3","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string"}},{"name":"subformat","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract in the requested format","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.get","description":"Get a data contract"}],"x-since":"7.13.4"},"delete":{"tags":["Contracts"],"summary":"Delete a contract (path form)","description":"**Since v9.94.1** — Identical to `DELETE /v4/contracts?contractId=…&version=…` in every respect — same auth, same org resolution, same force semantics, same responses — and delegates to the same handler. It exists because `GET /v4/contracts/{contractId}` does, and a client that reasonably inferred the matching DELETE previously got a 500 from the wrong-method catch-all rather than a route (#1434, #1439).\n\n`version` is required: a delete that guessed which version you meant, or removed all of them, is not a default anybody should get by omission.","operationId":"deleteByPath_1","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"force","in":"query","description":"See the collection form; semantics are identical.","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Contract deleted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"version was not supplied","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract, version or organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Referenced by data products and force is not set","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete a data contract"}],"x-since":"9.94.1"}},"/v4/contracts/{contractId}/verify-signature":{"get":{"tags":["Verification"],"summary":"Verify signature on a stored contract (public)","description":"**Since v7.31.0** — Verifies the digital signature embedded in the specified contract, resolved by id across all storage. No authentication required — contract ids are unguessable UUIDs. Omit version for the latest.","operationId":"verifyContract","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification result","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"signature.verify","description":"Verify signature on a stored contract"}],"x-since":"7.31.0"}},"/v4/contracts/{contractId}/products":{"get":{"tags":["Contracts"],"summary":"List the data products using a contract","description":"**Since v8.19.1** — Returns every data product that references this contract, and for each one the ports that reference it with the direction of use.\n\nThree ODPS shapes are matched:\n- `outputPorts[].contractId` — the product publishes under this contract (`output`)\n- `outputPorts[].inputContracts[].id` — the output port consumes this contract (`input`)\n- `inputPorts[].contractId` or `inputPorts[].id` — (`input`)\n\nThe match is version-agnostic by default; pass `version` to narrow to ports pinning that version. A port that pins no version always matches, since it references every version.\n\nA contract used by nothing returns `products: []` with a 200, not a 404.\n\nDistinct from `GET /v4/contracts/delete-check`, which is a pre-delete check: it matches only `outputPorts[].contractId`, requires an exact version match, and reports no direction.","operationId":"productsUsingContract","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Narrow to ports referencing this contract version","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The products using this contract, each with its referencing ports","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.used-by","description":"List the data products that use a contract"}],"x-since":"8.19.1"}},"/v4/contracts/supported-databases":{"get":{"tags":["Contracts"],"summary":"List supported JDBC databases","description":"**Since v7.13.4** — Returns the list of supported database types for JDBC contract creation.","operationId":"getSupportedDatabases","responses":{"200":{"description":"List of supported database types","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.database.list","description":"List supported JDBC databases"}],"x-since":"7.13.4"}},"/v4/contracts/maturity-level":{"get":{"tags":["Contracts"],"summary":"Measure contract maturity level (OMMS v0.2.0)","description":"**Since v4.0.0** — Returns a maturity level (0-5) for the specified contract using the OMMS v0.2.0 maturity model. Includes policy evaluation results and level caps. Pass org or orgId for organization contracts.","operationId":"getMaturityLevel_1","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Maturity assessment result with policy results","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.get","description":"Measure contract maturity level"}],"x-since":"4.0.0"}},"/v4/contracts/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get contract lifecycle history (v4, born-deprecated)","description":"**Since v7.1.6** — Verbatim copy of GET /v1/contracts/lifecycle.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getContractLifecycle","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.contract.list","description":"Get contract lifecycle history"}],"x-since":"7.1.6","x-sunset":"2027-01-01"}},"/v4/contracts/delete-check":{"get":{"tags":["Contracts"],"summary":"Pre-delete dependency check","description":"**Since v7.13.4** — Returns prior versions and referencing products for a contract, so the client can show a comprehensive delete confirmation modal. Read-only — no mutation.","operationId":"deleteCheck_1","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delete check result with prior versions and referencing products","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete.check","description":"Pre-delete dependency check"}],"x-since":"7.13.4"}},"/v4/contracts/compare":{"get":{"tags":["Contracts"],"summary":"Compare two contracts","description":"**Since v7.13.4** — Compares two data contracts and returns a DiffResult. Pass org or orgId to compare organization contracts.","operationId":"compareContracts","parameters":[{"name":"id1","in":"query","required":true,"schema":{"type":"string"}},{"name":"version1","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage1","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"id2","in":"query","required":true,"schema":{"type":"string"}},{"name":"version2","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage2","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"all"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"DiffResult JSON with differences and suggested version","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or a contract or version not found on either side of the compare","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Comparison failure","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.compare","description":"Compare two contracts"}],"x-since":"7.13.4"}},"/v4/comments/tasks":{"get":{"tags":["Comments"],"summary":"List tasks for the authenticated user","description":"**Since v5.0.0** — Returns task assignments (from `@[email]!` mentions) for the currently authenticated user.\n\n`status` selects the slice: `open` (the default, and exactly what this returned before #1447), `completed`, or `all`. An unrecognised value is rejected with 400 rather than coerced to the default — a typo must not silently return the wrong set.\n\nEach row carries `taskCompleted` and, when it is true, `taskCompletedAt`, so the two states are distinguishable without a second call.\n\nThe row's `id` is the **mention** id and `commentId` is the comment — they are different things, and the reply and complete verbs take different ones. The comment-derived fields (`anchorType`, `body`, `artifactKind`, `artifactId`, `artifactName`, `artifactVersion`, `orgSlug`, `author`, `resolvedBy`, `resolvedByUser`) are written by the same projection writer as `GET /v4/comments/my-threads`, so the two cannot report different subsets (#1497 / #1500).\n\n**The response is not paged and is not bounded.** Neither this endpoint nor `GET /v4/users/me/messages` pages, and returning everything keeps the \"my stuff\" endpoints consistent rather than making this one the odd one out. A long-lived account accumulates tasks indefinitely, so this is worth revisiting — for all of them together, not one at a time.","operationId":"listTasks","parameters":[{"name":"status","in":"query","description":"open (default), completed, or all","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Task list for the requested status","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unrecognised `status`","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.task.list","description":"List the user's open comment tasks"}],"x-since":"5.0.0"}},"/v4/comments/profile":{"get":{"tags":["Comments"],"summary":"Read a profile message thread","description":"**Since v9.45.0** — Returns the PROFILE conversation between the authenticated caller and `targetHandle` — top-level messages **and** replies, resolved and unresolved, oldest first.\n\n**An organization is required** (#1453) — pass `org` (slug) or `orgId`. PROFILE threads are stored and read per org, so there is no org-less form of this conversation, and a personal workspace cannot read one. The other party must also share that organization with you and have a public profile, which is the same predicate `GET /v4/orgs/members` reports as `messageable`.\n\n`GET /v4/comments` cannot serve this: a PROFILE comment has `artifactKind` and `artifactId` set to null by design, and that endpoint requires both, so no value of either would ever match one.\n\nBoth directions of the conversation are returned. A reply the other party sent back is part of the same thread, so a one-directional read would show each side half a conversation.\n\n**Gating matches the create side.** A caller who could not have written the message cannot read it: they must be a member of `org`, the handle must belong to a public profile, and the two must share that org. All three failures return the same 404 body — an unknown handle, a profile that is not public and a person outside the org are deliberately indistinguishable, or this endpoint becomes the profile-enumeration oracle `/v4/users/{handle}/public` was built to refuse.\n\n**A conversation with no messages is a 200 with `[]`, not a 404.** \"No messages yet\" is a normal state for a conversation view.","operationId":"listProfileThread","parameters":[{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"targetHandle","in":"query","description":"The other party's public handle","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The conversation, oldest first, possibly empty","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CommentResponse"}}}}},"400":{"description":"No org given, or no targetHandle","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Not authenticated","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such messageable profile — unknown handle, not public, or not in this org; the three are indistinguishable","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.profile.list","description":"Read the profile message thread between the caller and a handle"}],"x-since":"9.45.0"}},"/v4/comments/my-threads":{"get":{"tags":["Comments"],"summary":"List threads for the authenticated user","description":"**Since v5.0.7** — Returns top-level comment threads where the user is the author, was @mentioned, or is the addressee of a PROFILE message.\n\n`status` selects the slice: `open` (the default, and exactly what this returned before #1447), `completed`, or `all`. For a thread the closed state is **resolved** — `completed` therefore means resolved here, while on `GET /v4/comments/tasks` it means the task was ticked off. An unrecognised value is rejected with 400 rather than coerced.\n\nEach row carries `isResolved` and, when it is true, `resolvedAt`, `resolvedBy` and `resolvedByUser`, so the two states are distinguishable without a second call.\n\n`resolvedBy` is the resolver's numeric id and `resolvedByUser` is the same person in the same shape as `author` (#1486) — the id answers \"did I resolve this?\", the object answers \"who resolved this?\". `resolvedByUser` is absent on an unresolved thread, and its `handle` obeys the same public-profile gate as `author`'s.\n\nEach row carries `anchorType` (`ARTIFACT` / `SECTION` / `ELEMENT` / `PROFILE`) so a PROFILE thread is identified directly rather than inferred from null artifact keys (#1500), plus `orgSlug` and `artifactName` for rendering. `artifactName` is `\"\"` — not null — when there is no artifact to name.\n\n**The response is not paged and is not bounded** — see the note on `GET /v4/comments/tasks`.","operationId":"listMyThreads","parameters":[{"name":"status","in":"query","description":"open (default), completed, or all","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Thread list for the requested status","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unrecognised `status`","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.thread.list","description":"List the user's open comment threads"}],"x-since":"5.0.7"}},"/v4/comments/count":{"get":{"tags":["Comments"],"summary":"Count unresolved comments","description":"**Since v5.0.0** — Returns the number of unresolved top-level comment threads for an artifact.","operationId":"countUnresolved","parameters":[{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"artifactKind","in":"query","description":"Artifact kind","required":true,"schema":{"type":"string"}},{"name":"artifactId","in":"query","description":"Artifact UUID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unresolved count","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Feature disabled","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"comment.count.get","description":"Count unresolved comment threads"}],"x-since":"5.0.0"}},"/v4/catalogs/properties":{"get":{"tags":["External Catalogs"],"summary":"Discover available properties on a catalog vendor","description":"**Since v7.2.0** — Probes the catalog to discover which properties are available on datasets, fields, and contacts.","operationId":"discoverProperties","parameters":[{"name":"vendor","in":"query","description":"Catalog vendor","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"catalog.property.list","description":"Discover available properties on a catalog vendor"}],"x-since":"7.2.0"}},"/v4/catalogs/datasets":{"get":{"tags":["External Catalogs"],"summary":"List datasets from an external catalog","description":"**Since v7.2.0** — Returns a list of datasets from the specified catalog vendor. Credentials are resolved from the user's or organization's integration settings.","operationId":"listDatasets","parameters":[{"name":"vendor","in":"query","description":"Catalog vendor (e.g., zeenea)","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Dataset list returned","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown vendor","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Catalog credentials not configured","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"Upstream catalog API error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"catalog.dataset.list","description":"List datasets from an external catalog"}],"x-since":"7.2.0"}},"/v4/badges":{"get":{"tags":["Badges"],"summary":"List the badge catalog","description":"**Since v9.9.0** — The badges that can be earned, enabled only, in catalog order. Design-time data — identical for every caller, so no per-user filtering applies. `imageUrl` points at `/v4/badges/{id}/image`. Attribution configuration (`criteriaSource`, thresholds) is deliberately not exposed here; it belongs to the admin surface.","operationId":"catalog","responses":{"200":{"description":"The catalog","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeCatalogEntry"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeCatalogEntry"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.catalog.list","description":"List the badge catalog"}],"x-since":"9.9.0"}},"/v4/badges/{badgeId}/image":{"get":{"tags":["Badges"],"summary":"Serve a badge's art (public)","description":"**Since v9.9.0** — The 512x512 PNG for a badge template. This is the *source* art — the unbaked class image. The per-award baked credential, which is what verifies standalone and imports into Credly or Sessionize, is served separately once WB3 #1246 lands. **Unauthenticated by design**: every Open Badges credential embeds `achievement.image` pointing here, so an external consumer — Credly, Sessionize, a link preview — fetches it with no token. An unknown id is a 404.","operationId":"image","parameters":[{"name":"badgeId","in":"path","description":"Badge id","required":true,"schema":{"type":"string"},"example":"podemaster_bronze"}],"responses":{"200":{"description":"The PNG","content":{"image/png":{"schema":{"type":"string","format":"byte"}}}},"404":{"description":"No such badge, or its art is missing","content":{"image/png":{"schema":{"type":"string","format":"byte"}}}}},"x-intent":[{"name":"badge.image.get","description":"Serve a badge's source art"}],"x-since":"9.9.0"}},"/v4/badges/{badgeId}/class":{"get":{"tags":["Badges"],"summary":"Open Badges 2.0 BadgeClass (public)","description":"**Since v9.54.0** — The BadgeClass document an assertion's `badge` property points at. Design-time data, identical for every holder, so it carries nothing about who earned it. **Unauthenticated by design** — OB 2.0 requires it to resolve for the assertion to verify. An unknown id is a 404.","operationId":"badgeClass","parameters":[{"name":"badgeId","in":"path","description":"Badge template id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The badge class","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"No such badge","content":{"application/json":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"badge.class.get","description":"Public Open Badges 2.0 BadgeClass"}],"x-since":"9.54.0"}},"/v4/badges/unseen":{"get":{"tags":["Badges"],"summary":"List unseen badge awards","description":"**Since v9.11.0** — The caller's awards with no `seen_at`, newest first, denormalised with the template's name, tier and art so the celebration popup renders from this response alone. This matters most for badges granted asynchronously — Top Dog is awarded by a scheduled job at period close, quite possibly with no browser open — which without a queue would be silently missed. Returns `[]`, never null.","operationId":"unseen","responses":{"200":{"description":"Unseen awards, possibly empty","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UnseenBadgeAward"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UnseenBadgeAward"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.award.unseen","description":"List awards the caller has not been shown"}],"x-since":"9.11.0"}},"/v4/badges/me":{"get":{"tags":["Badges"],"summary":"List my badges","description":"**Since v9.10.0** — The caller's earned badges, newest first. Evaluation runs first, so a user who qualified before the feature shipped is caught up on their first view rather than waiting for their next artifact. Self-scoped deliberately: there is no route that lets one user enumerate another's achievements. `id` is the award id, `badgeId` the catalog id.","operationId":"myBadges","responses":{"200":{"description":"The caller's awards","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeAwardResponse"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeAwardResponse"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.award.list","description":"List the caller's earned badges"}],"x-since":"9.10.0"}},"/v4/badges/issuer":{"get":{"tags":["Badges"],"summary":"Open Badges 2.0 issuer Profile (public)","description":"**Since v9.54.0** — The issuer Profile a BadgeClass points at. Static, and about the Workbench rather than about any person. **Unauthenticated by design** — OB 2.0 requires it to resolve for the assertion to verify.","operationId":"issuer","responses":{"200":{"description":"The issuer profile","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}}},"x-intent":[{"name":"badge.issuer.get","description":"Public Open Badges 2.0 issuer Profile"}],"x-since":"9.54.0"}},"/v4/badges/awards/{awardId}/image":{"get":{"tags":["Badges"],"summary":"Download a baked badge","description":"**Since v9.12.0** — The award's PNG with its Open Badges 3.0 credential embedded in an `openbadges` iTXt chunk. This is the file that verifies standalone and imports into Credly or Sessionize — an unbaked PNG is just a picture, which is why this path is distinct from `/v4/badges/{id}/image` (the generic catalog art). Owner only: the credential names its subject, so another user's award returns 404 rather than confirming it exists. Baking is idempotent — the file always carries exactly one credential.","operationId":"bakedAwardImage","parameters":[{"name":"awardId","in":"path","description":"Award id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The baked PNG","content":{"image/png":{"schema":{"type":"string","format":"byte"}}}},"401":{"description":"Missing or invalid JWT","content":{"image/png":{"schema":{"type":"string","format":"byte"}}}},"404":{"description":"No such award for this caller","content":{"image/png":{"schema":{"type":"string","format":"byte"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"badge.award.image","description":"Download an award's baked badge"}],"x-since":"9.12.0"}},"/v4/badges/awards/{awardId}/credential":{"get":{"tags":["Badges"],"summary":"Open Badges 3.0 credential (public)","description":"**Since v9.54.0** — The OB 3.0 Verifiable Credential for one award, at the URL that credential names as its own `id`. **Unauthenticated by design**, for the same reason as the assertion above. This is the same JSON baked into the award's PNG. The subject is pseudonymous — never an email. An unknown id is a 404.","operationId":"credential","parameters":[{"name":"awardId","in":"path","description":"Award id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The credential","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"No such award, or it carries no credential","content":{"application/json":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"badge.credential.get","description":"Public Open Badges 3.0 credential"}],"x-since":"9.54.0"}},"/v4/badges/awards/{awardId}/assertion":{"get":{"tags":["Badges"],"summary":"Open Badges 2.0 hosted assertion (public)","description":"**Since v9.54.0** — The hosted-verification document for one award. **Unauthenticated by design** — this is the callback an Open Badges 2.0 consumer fetches to verify a badge, so it has to resolve for anyone. `verification.type` is `HostedBadge` and `id` is this document's own URL, which is what makes the comparison possible. The recipient is a salted SHA-256, never a readable address. Award ids are random UUIDv4, so this is not an enumerable listing of awards. An unknown id is a 404.","operationId":"assertion","parameters":[{"name":"awardId","in":"path","description":"Award id","required":true,"schema":{"type":"string"}},{"name":"Accept","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The assertion (every non-browser client)","content":{"*/*":{"schema":{"type":"object"}}}},"302":{"description":"A browser-shaped `Accept` is redirected to the human badge page","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No such award, or its badge is gone","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"badge.assertion.get","description":"Public Open Badges 2.0 hosted assertion"}],"x-since":"9.54.0"}},"/v4/artifacts":{"get":{"tags":["Artifacts"],"summary":"List the caller's artifacts (contracts + products) across personal + every org","description":"**Since v7.0.10** — Returns a unified header list of every contract and product the caller can see — their personal storage plus every organization they are a member of. Detail and YAML are fetched per artifact via /v3/{contracts,products}/{id}.","operationId":"listArtifacts","responses":{"200":{"description":"The caller's artifact headers plus a total count","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ArtifactListResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ArtifactListResponse"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"artifact.list","description":"List all artifacts across personal and org storage"}],"x-since":"7.0.10"}},"/v4/artifacts/supported-versions":{"get":{"tags":["Artifacts"],"summary":"List supported ODCS/ODPS apiVersions","description":"**Since v7.48.0** — Returns the ODCS and ODPS apiVersion values the bundled validator supports, derived from the packaged JSON schemas, grouped by standard with each standard's current/default flagged. Consumed by the Workbench editor's API-version combobox (WB#866).\n\nPer standard: `current` is the version artifact creation stamps and the one clients should default to; `latest` is the newest version whose schema is bundled, which may still be an unapproved draft; `versions` is the flat, **oldest-first** string array (unchanged since #882 — existing clients keep working); `versionDetails` (#1074) is the same set **newest-first** with a `status` of `draft`, `approved` or `deprecated` and a `default` flag, so a client can offer a draft version without implying it is final. `status` is derived from `VersionK.DRAFT_VERSIONS` / `DEPRECATED_VERSIONS`, so promoting a draft is a one-set edit rather than a controller change.","operationId":"getSupportedVersions","responses":{"200":{"description":"Supported versions per standard, e.g. {\"odcs\": {\"current\": \"v3.1.0\", \"latest\": \"v3.2.0\", \"versions\": [\"v3.1.0\", ...], \"versionDetails\": [{\"version\": \"v3.2.0\", \"status\": \"draft\", \"default\": false}, ...]}, \"odps\": {...}}","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"artifact.versions.list","description":"List supported ODCS/ODPS apiVersions"}],"x-since":"7.48.0"}},"/v4/admin/validate":{"get":{"tags":["Administration"],"summary":"Force-validate a user (v4 admin)","description":"**Since v7.13.0** — Admin force-validates a user account by email, bypassing the validation code.","operationId":"forceValidateUser","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User successfully validated (or already validated)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.validate","description":"Force-validate a user account (admin)"}],"x-since":"7.13.0"}},"/v4/admin/users":{"get":{"tags":["Administration"],"summary":"List all users (v4 admin)","description":"**Since v7.13.0** — Returns all registered users with full details.","operationId":"listUsers_1","responses":{"200":{"description":"List of AdminUserResponse objects","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserResponse"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.list","description":"List all users (admin)"}],"x-since":"7.13.0"},"delete":{"tags":["Administration"],"summary":"Delete a user (v4 admin)","description":"**Since v7.13.0** — Deletes a user by email. User data is backed up before deletion.","operationId":"deleteUser","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User successfully deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.delete","description":"Delete a user by email (admin)"}],"x-since":"7.13.0"}},"/v4/admin/users/{id}":{"get":{"tags":["Administration"],"summary":"Get a user (v4 admin)","description":"**Since v9.92.0** — Returns the full admin record for one user — the same AdminUserResponse shape the list returns, including `standardChannel` as stored.","operationId":"getUser","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The user's AdminUserResponse","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AdminUserResponse"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.get","description":"Get one user's full admin record"}],"x-since":"9.92.0"}},"/v4/admin/users/active":{"get":{"tags":["Administration"],"summary":"List recently active users (v4 admin, experimental)","description":"**Since v7.13.0** — Returns users who made any API call within the specified time window. Defaults to the last 60 minutes.","operationId":"activeUsers","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":60}}],"responses":{"200":{"description":"List of AdminUserResponse objects for active users","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserResponse"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.list-active","description":"List recently active users (admin)"}],"x-since":"7.13.0"}},"/v4/admin/test-runs/health":{"get":{"tags":["Administration"],"summary":"Test suite health, as the alert job sees it (admin)","description":"**Since v9.117.11** — Every suite with a run in the last 30 days, grouped as `(app, source.process, provenance)`. `redStreak` counts consecutive red finished runs (a run that executed zero tests is red); `silent` means the latest report is older than twice the median gap between the suite's recent runs. Runs with provenance `local` are excluded.","operationId":"health","responses":{"200":{"description":"One entry per suite","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestRunSuiteHealth"}}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestRunSuiteHealth"}}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestRunSuiteHealth"}}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.testRuns.health","description":"See every test suite's red streak, cadence and silence, as the alert job does"}],"x-since":"9.117.11"}},"/v4/admin/signup-requests":{"get":{"tags":["Administration"],"summary":"List signup requests","description":"**Since v7.13.0** — Returns a page of signup requests, optionally filtered by status (pending/approved/rejected/expired — expired = auto-expired stale pending, #1003). Accounts belonging to the Playwright E2E suites (e2e-test-*@actianlabs.com, e2e-admin@actianlabs.com, e2e-user@actianlabs.com) are HIDDEN by default; pass includeE2e=true to see them. The filter is applied server-side, so totalElements and totalPages describe the filtered set.","operationId":"list_12","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeE2e","in":"query","description":"Include accounts belonging to the Playwright E2E suites. Defaults to false, which hides e2e-test-*@actianlabs.com plus the fixed e2e-admin@ and e2e-user@ accounts from both the page and its count.","required":false,"schema":{"type":"boolean","default":false}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}}],"responses":{"200":{"description":"Paged list","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.list","description":"List signup requests"}],"x-since":"7.13.0"}},"/v4/admin/shotz":{"get":{"tags":["Administration"],"summary":"List camera frames (v4 admin)","description":"**Since v7.15.0** — Returns metadata for every frame uploaded by the \"dash on the go\" device via POST /v4/health/shotz, newest first, with EXIF GPS latitude/longitude surfaced when the frame is geotagged.","operationId":"listShotz","responses":{"200":{"description":"JSON array of ShotzResponse objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.shotz.list","description":"List device camera frames (admin)"}],"x-since":"7.15.0"}},"/v4/admin/shotz/{id}":{"get":{"tags":["Administration"],"summary":"Stream a camera frame (v4 admin)","description":"**Since v7.15.0** — Streams the JPEG bytes of a single uploaded frame by id (the id returned by GET /v4/admin/shotz).","operationId":"getShotz","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The JPEG image","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No frame with that id","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.shotz.get","description":"Stream one device camera frame (admin)"}],"x-since":"7.15.0"},"delete":{"tags":["Administration"],"summary":"Delete a camera frame (v4 admin)","description":"**Since v7.49.0** — Deletes a single uploaded frame by id (the id returned by GET /v4/admin/shotz). The backing file is removed; the operation is not undoable (#880).","operationId":"deleteShotz","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Frame deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"No frame with that id","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.shotz.delete","description":"Delete one device camera frame (admin)"}],"x-since":"7.49.0"}},"/v4/admin/podemites/totals":{"get":{"tags":["Podemites"],"summary":"List Podemite totals (admin)","description":"**Since v9.53.0** — Lifetime Podemite totals for every user holding any, highest first. The admin counterpart of GET /v4/credits/balances.","operationId":"getAllTotals","responses":{"200":{"description":"Totals returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"podemite.totals.list","description":"List every user's Podemite total (admin)"}],"x-since":"9.53.0"}},"/v4/admin/plugins":{"get":{"tags":["Administration"],"summary":"List all plugin registrations","description":"**Since v9.3.0** — Every registration across every organization, grouped by reverse-DNS plugin id, with activation and veto state. platform-admin only.","operationId":"list_13","responses":{"200":{"description":"Registrations grouped by plugin id","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.plugins.list","description":"Every plugin registration across every organization"}],"x-since":"9.3.0"}},"/v4/admin/orgs":{"get":{"tags":["Administration"],"summary":"List all organizations (v4 admin)","description":"**Since v7.17.0** — Returns every organization in the system regardless of the caller's memberships, in the same shape as GET /v4/orgs/{slug} plus a numeric \"members\" field (count of memberships, excluding pending invitations) so the admin orgs panel can render \"N members\". The admin orgs panel uses this instead of the membership-scoped GET /v4/orgs/mine.","operationId":"listAllOrgs","responses":{"200":{"description":"JSON array of org objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.org.list","description":"List ALL organizations (admin)"}],"x-since":"7.17.0"}},"/v4/admin/onboarding/journeys":{"get":{"tags":["Administration"],"summary":"Onboarding journeys","description":"**Since v8.16.7** — One row per stitched journey (visitor and/or email) with per-stage first-seen timestamps, reminder count, and a derived status (in_progress, converted, stuck_after_approval, dropped). status=stuck filters to stuck_after_approval. excludeTest (default true) drops E2E test journeys before sort/paging so the totals reflect real users.","operationId":"journeys","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":30}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"excludeTest","in":"query","required":false,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Paged journey rows","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"onboarding.journeys","description":"Onboarding journeys: one row per visitor/email"}],"x-since":"8.16.7"}},"/v4/admin/onboarding/funnel":{"get":{"tags":["Administration"],"summary":"Onboarding funnel","description":"**Since v8.16.7** — Per-stage distinct-journey counts over the trailing window, with step-to-step conversion % and headline totals (visitors, requests, approvals, registrations, conversions). excludeTest (default true) drops E2E test journeys before counts/conversions are computed.","operationId":"funnel","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":30}},{"name":"excludeTest","in":"query","required":false,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Funnel report","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"onboarding.funnel","description":"Onboarding funnel: per-stage counts and conversion rates"}],"x-since":"8.16.7"}},"/v4/admin/onboarding/funnel/stage/{stage}":{"get":{"tags":["Administration"],"summary":"Onboarding stage drill-down","description":"**Since v8.16.11** — The journeys that reached {stage} within the window, each annotated with the next step it took — nextStage is the earliest later ordered stage the journey reached, or null when it stopped here (dropped). reachedCount is the true total; droppedCount counts journeys that stopped at this stage; items is capped at 200. days (default 30) and excludeTest (default true) match /funnel.","operationId":"stageDetail","parameters":[{"name":"stage","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":30}},{"name":"excludeTest","in":"query","required":false,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Stage drill-down report","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown stage","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"onboarding.stageDetail","description":"Onboarding stage drill-down: who reached a stage + their next step"}],"x-since":"8.16.11"}},"/v4/admin/onboarding/anomalies":{"get":{"tags":["Administration"],"summary":"Onboarding anomalies","description":"**Since v8.16.7** — Things going wrong: FAILED Email Log rows for onboarding mails, v4 register failures/rollbacks, approved invitees with 3 reminders exhausted who never joined, and unverified accounts whose verification code expired and was never resent. excludeTest (default true) drops rows belonging to E2E test accounts, using the same prefix rule as /funnel and /journeys — register failures are matched on the addresses named in the activity text.","operationId":"anomalies","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":7}},{"name":"excludeTest","in":"query","required":false,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Anomaly report","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"onboarding.anomalies","description":"Onboarding anomalies: failures across the funnel"}],"x-since":"8.16.7"}},"/v4/admin/logs":{"get":{"tags":["Administration"],"summary":"Get activity logs (v4 admin)","description":"**Since v7.0.55** — Returns recent activity log entries. v4 replacement for the deprecated GET /v2/admin/logs.","operationId":"getActivityLogs","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"userId","in":"query","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of ActivityLog objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.log.list","description":"Get activity logs (admin)"}],"x-since":"7.0.55"}},"/v4/admin/invitation-history":{"get":{"tags":["Administration"],"summary":"List invite-driven signup history","description":"**Since v7.13.0** — Paginated (20 per page), searchable audit trail of every user who signed up with an invitation code. Each row carries the invitee email, the code used, the code type (personal | admin), the inviter email (em dash for admin codes), and the signup date. The optional 'search' parameter filters server-side across code, inviter email, and invitee email. Newest signups first. Accounts belonging to the Playwright E2E suites (e2e-test-*@actianlabs.com, e2e-admin@actianlabs.com, e2e-user@actianlabs.com) are HIDDEN by default; pass includeE2e=true to see them. The filter is applied server-side, so totalElements and totalPages describe the filtered set.","operationId":"list_14","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeE2e","in":"query","description":"Include accounts belonging to the Playwright E2E suites. Defaults to false, which hides e2e-test-*@actianlabs.com plus the fixed e2e-admin@ and e2e-user@ accounts from both the page and its count.","required":false,"schema":{"type":"boolean","default":false}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"Paged history","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-history.list","description":"List invite-driven signup history (admin)"}],"x-since":"7.13.0"}},"/v4/admin/interactions":{"get":{"tags":["Admin"],"summary":"Export Governance Coach interactions (admin)","description":"**Since v9.8.0** — Pages the pseudonymous Governance Coach interaction store for a date range, for RAG corpus and model-evaluation work. Paging is keyset-based over `(day, id)`, not `OFFSET`: rows inserted while a scan is in progress can neither duplicate an already-returned row nor displace one. For a provably exact reconstruction set `to` to a day that has already closed — `day` is server-derived at date precision, so a closed range can never gain a row. Omitting both bounds applies a 30-day window rather than scanning the table. `limit` defaults to 100 and is clamped to 1000.\n\n**Identity (amended by #1483).** The table stores **no user identity, no IP, no user-agent and no artifact id, and never will** — `pseudonymId` remains the only per-person correlation key, and there is deliberately no user filter. What changed is the organization: each row may carry `orgHash`, a peppered HMAC-SHA256 of the org the question was asked in, so usage is understandable per company. Pass `org` (a slug or UUID) to narrow to one — it is hashed server-side and the stored hash is never reversed. `orgHash` is null on rows written before #1483, on questions asked in a personal workspace, and whenever the feature is switched off. Note that raw rows are purged once past `bitol.coach.retention-days` (default 180), so exports must run inside that window. Error responses carry `{message, reason}` with reason `invalid_request`.","operationId":"exportInteractions","parameters":[{"name":"from","in":"query","description":"Inclusive start day (ISO `yyyy-MM-dd`); defaults to `to` minus 30 days","required":false,"schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Inclusive end day (ISO `yyyy-MM-dd`); defaults to today, UTC","required":false,"schema":{"type":"string","format":"date"}},{"name":"limit","in":"query","description":"Page size; defaults to 100, clamped to 1000","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cursor","in":"query","description":"Opaque keyset cursor returned as `nextCursor` by the previous page","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1483 — narrow to one organization, by slug or UUID. Hashed server-side before the query; the stored hash is never reversed.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A page of interactions","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InteractionExportPage"}}}},"400":{"description":"A malformed `from`, `to` or `limit`, a bad range, or a bad cursor: reason `invalid_request`.","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.interaction.export","description":"Page Governance Coach interactions for a date range (admin)"}],"x-since":"9.8.0"}},"/v4/admin/interactions/rollup":{"get":{"tags":["Admin"],"summary":"Weekly Governance Coach rollup (admin)","description":"**Since v9.117.8** — Returns the weekly counters the retention purge leaves behind, for a date range. Raw interactions older than `bitol.coach.retention-days` (default 180) are deleted on purpose; before deletion each one is counted into `coach_interaction_rollup`, one counter per (retrieved path, maturity gap, section, ISO week). This is the only way to read those counters, so it is what an admin page shows for any stretch older than the export can reach.\n\n**What a row can and cannot say.** Each row has exactly five fields: `retrievedPath`, `maturityGap`, `section`, `isoWeek`, `count`. There is no pseudonym, session, organization or text, and there never can be, because none of those survive into the rollup. A row answers \"how much, of what kind, in which week\", never \"who\" or \"which company\".\n\n**Range.** `from` and `to` behave exactly as on `GET /v4/admin/interactions`: `to` defaults to today (UTC), `from` to 30 days before `to`, and `from` after `to` is a 400. The rollup cannot be split below a week, so the range is widened to whole ISO weeks, reported back as `fromWeek` and `toWeek`. A range inside the retention window is answered too, with whatever counters exist there: the two stores overlap, so a caller never has to know where the boundary is to pick an endpoint. Error responses carry `{message, reason}` with reason `invalid_request`, as the export's do.","operationId":"rollup","parameters":[{"name":"from","in":"query","description":"Inclusive start day (ISO `yyyy-MM-dd`); defaults to `to` minus 30 days","required":false,"schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Inclusive end day (ISO `yyyy-MM-dd`); defaults to today, UTC","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"The weekly counters for the range","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CoachInteractionRollupPage"}}}},"400":{"description":"A malformed `from` or `to`, or `from` after `to`: reason `invalid_request`.","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required; an admin `X-API-KEY` is refused on /v4/admin","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.interaction.rollup","description":"Read the weekly Governance Coach counters that survive retention (admin)"}],"x-since":"9.117.8"}},"/v4/admin/emails":{"get":{"tags":["Administration"],"summary":"Get email logs (v4 admin)","description":"**Since v7.13.0** — Returns recent email delivery logs with recipient, subject, status, and timestamp.","operationId":"getEmailLogs","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"JSON array of EmailLog objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.email-log.list","description":"Get email delivery logs (admin)"}],"x-since":"7.13.0"}},"/v4/admin/demo/pushes":{"get":{"tags":["Administration"],"summary":"Every demo push, newest first","description":"**Since v9.108.0** — Who pushed, when, with which options, and the per-bucket counts — dry runs included, flagged as such. The dry run is the number an admin acted on, so omitting it would leave 'what did the panel say before you pressed it' unanswerable.","operationId":"pushes","responses":{"200":{"description":"The push records, newest first","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"demo.pushHistory","description":"Read back every demo push and what it did"}],"x-since":"9.108.0"}},"/v4/admin/credits/balances":{"get":{"tags":["Credits"],"summary":"List all Credits balances (admin)","description":"**Since v7.44.0** — Admin view of all users' Credits balances.","operationId":"getAllBalances","responses":{"200":{"description":"Balance list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.credit-balance.list","description":"List all Credits balances (admin)"}],"x-since":"7.44.0"}},"/v3/products/{productId}":{"get":{"tags":["Products"],"summary":"Get a data product (v3)","description":"**Since v3.0.0** — Retrieves a data product by ID. Pass org or orgId for organization products.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_4","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"ODPS YAML content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Product or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.get","description":"Retrieve a data product by ID"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/products/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get product lifecycle history (v3)","description":"**Since v3.1.4** — Returns the lifecycle history of a data product. Pass org or orgId to query org-scoped lifecycle entries.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getProductLifecycle_1","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of lifecycle entries; each entry carries an `actor` object {userId, email, firstName, lastName} resolved from the recorded user (null when the user no longer exists)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.product.list","description":"Get product lifecycle history"}],"x-since":"3.1.4","x-sunset":"2027-01-01"}},"/v3/products/delete-check":{"get":{"tags":["Products"],"summary":"Pre-delete dependency check (v3)","description":"**Since v3.5.0** — Returns prior versions and referenced contracts for a product, so the client can show a comprehensive delete confirmation modal. Read-only — no mutation.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteCheck_2","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delete check result with prior versions and referenced contracts","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.delete-check","description":"Check product dependencies before delete"}],"x-since":"3.5.0","x-sunset":"2027-01-01"}},"/v3/maturity-history":{"get":{"tags":["Maturity History"],"summary":"Get maturity history","description":"**Since v4.3.0** — Returns daily maturity level distribution snapshots for contracts or products. Pass org or orgId for org-scoped data; omit for personal data. Defaults to the last 90 days if from/to are omitted.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getMaturityHistory_1","parameters":[{"name":"artifactType","in":"query","description":"Artifact type: 'contract' or 'product'","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start date (yyyy-MM-dd), defaults to 90 days ago","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"End date (yyyy-MM-dd), defaults to today","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of {date, maturityLevel, count} objects","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid artifactType or date format","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.history.get","description":"Get maturity distribution history"}],"x-since":"4.3.0","x-sunset":"2027-01-01"}},"/v3/github/verify-access":{"get":{"tags":["Automation"],"summary":"Verify repository access","description":"**Since v3.2.3** — Verifies that the GitHub token has sufficient permissions to access and modify the repository.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"verifyAccess_1","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Access verification result","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.verify-access","description":"Verify GitHub repository access"}],"x-since":"3.2.3","x-sunset":"2027-01-01"}},"/v3/github/actions/runs":{"get":{"tags":["Automation"],"summary":"Get latest workflow run","description":"**Since v3.2.3** — Returns the status of the latest workflow run.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getLatestRun_1","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Latest workflow run status","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.run.get","description":"Get the latest workflow run"}],"x-since":"3.2.3","x-sunset":"2027-01-01"}},"/v3/contracts/{contractId}":{"get":{"tags":["Contracts"],"summary":"Get a data contract (v3)","description":"**Since v3.0.0** — Retrieves a contract by ID in the specified format. Pass org or orgId for organization contracts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_5","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string"}},{"name":"subformat","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract in the requested format","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.get","description":"Get a data contract"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/contracts/supported-databases":{"get":{"tags":["Contracts"],"summary":"List supported JDBC databases (v3)","description":"**Since v3.0.0** — Returns the list of supported database types for JDBC contract creation.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getSupportedDatabases_1","responses":{"200":{"description":"List of supported database types","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.database.list","description":"List supported JDBC databases"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/contracts/maturity-level":{"get":{"tags":["Contracts"],"summary":"Measure contract maturity level (v3, deprecated)","description":"**Since v3.0.0** — **Deprecated** — use `GET /v4/contracts/maturity-level` instead. Returns a maturity level (1-5) for the specified contract. Pass org or orgId for organization contracts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getMaturityLevel_2","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Maturity assessment result","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.get","description":"Measure contract maturity level"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/contracts/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get contract lifecycle history (v3)","description":"**Since v3.1.4** — Returns the lifecycle history of a data contract. Pass org or orgId to query org-scoped lifecycle entries.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getContractLifecycle_1","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JSON array of lifecycle entries; each entry carries an `actor` object {userId, email, firstName, lastName} resolved from the recorded user (null when the user no longer exists)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.contract.list","description":"Get contract lifecycle history"}],"x-since":"3.1.4","x-sunset":"2027-01-01"}},"/v3/contracts/delete-check":{"get":{"tags":["Contracts"],"summary":"Pre-delete dependency check (v3)","description":"**Since v3.4.0** — Returns prior versions and referencing products for a contract, so the client can show a comprehensive delete confirmation modal. Read-only — no mutation.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteCheck_3","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delete check result with prior versions and referencing products","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.delete.check","description":"Pre-delete dependency check"}],"x-since":"3.4.0","x-sunset":"2027-01-01"}},"/v3/contracts/compare":{"get":{"tags":["Contracts"],"summary":"Compare two contracts (v3)","description":"**Since v3.0.0** — Compares two data contracts and returns a DiffResult. Pass org or orgId to compare organization contracts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"compareContracts_1","parameters":[{"name":"id1","in":"query","required":true,"schema":{"type":"string"}},{"name":"version1","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage1","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"id2","in":"query","required":true,"schema":{"type":"string"}},{"name":"version2","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage2","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"all"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"DiffResult JSON with differences and suggested version","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not an org member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or a contract or version not found on either side of the compare","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Comparison failure","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.compare","description":"Compare two contracts"}],"x-since":"3.0.0","x-sunset":"2027-01-01"}},"/v3/catalogs/properties":{"get":{"tags":["External Catalogs"],"summary":"Discover available properties on a catalog vendor","description":"**Since v4.4.11** — Probes the catalog to discover which properties are available on datasets, fields, and contacts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"discoverProperties_1","parameters":[{"name":"vendor","in":"query","description":"Catalog vendor","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"catalog.property.list","description":"Discover available properties on a catalog vendor"}],"x-since":"4.4.11","x-sunset":"2027-01-01"}},"/v3/catalogs/datasets":{"get":{"tags":["External Catalogs"],"summary":"List datasets from an external catalog","description":"**Since v4.4.0** — Returns a list of datasets from the specified catalog vendor. Credentials are resolved from the user's or organization's integration settings.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listDatasets_1","parameters":[{"name":"vendor","in":"query","description":"Catalog vendor (e.g., zeenea)","required":true,"schema":{"type":"string"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Dataset list returned","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown vendor","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Catalog credentials not configured","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"Upstream catalog API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"catalog.dataset.list","description":"List datasets from an external catalog"}],"x-since":"4.4.0","x-sunset":"2027-01-01"}},"/v2/users/me/integrations":{"get":{"tags":["Publishing"],"summary":"Get all integration statuses","description":"**Since v2.12.0** — Returns a summary of which integrations are configured for the authenticated user.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getAllStatuses_2","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.list","description":"List all integration statuses"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/users/me/integrations/{key}/status":{"get":{"tags":["Publishing"],"summary":"Get integration status","description":"**Since v2.12.0** — Returns non-secret config, configured boolean, and last test result for the specified integration.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getStatus_2","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.get","description":"Get a single integration status"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/products/{productId}":{"get":{"tags":["Products"],"summary":"Get a data product (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/products/{productId} instead. Retrieves a data product by ID. Returns full ODPS YAML content.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_6","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"ODPS YAML content","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.get","description":"Retrieve a data product by ID"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/products/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get product lifecycle history (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/products/lifecycle instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getProductLifecycle_2","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of lifecycle entries","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.product.list","description":"Get product lifecycle history"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/products/{productId}":{"get":{"tags":["Organization Products"],"summary":"Get an organization product","description":"**Since v2.5.0** — Deprecated — use GET /v3/products/{productId}?org={slug} instead. Retrieves a product by ID from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_7","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"ODPS YAML content","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or product not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"product.get","description":"Retrieve a data product by ID"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/messages":{"get":{"tags":["Membership"],"summary":"List pending messages","description":"**Since v2.5.0** — Admin/owner views pending join requests and invitations.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listPendingMessages_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of pending messages","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.message.list","description":"List pending join requests and invitations"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/members":{"get":{"tags":["Membership"],"summary":"List organization members","description":"**Since v2.5.0** — Returns all members of the organization. Requires membership.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listMembers_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of members","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.list","description":"List organization members"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/integrations":{"get":{"tags":["Organization Settings"],"summary":"Get all org integration statuses","description":"**Since v2.12.0**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getAllStatuses_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.list","description":"List all org integration statuses"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/integrations/{key}/status":{"get":{"tags":["Organization Settings"],"summary":"Get org integration status","description":"**Since v2.12.0**\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getStatus_3","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"integration.get","description":"Get a single org integration status"}],"x-since":"2.12.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/contracts/{contractId}":{"get":{"tags":["Organization Contracts"],"summary":"Get an organization contract","description":"**Since v2.5.0** — Deprecated — use GET /v3/contracts/{contractId}?org={slug} instead. Retrieves a contract by ID in the specified format from the organization.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_8","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string"}},{"name":"subformat","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"Contract in requested format","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Not a member","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.get","description":"Get an organization contract"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/search":{"get":{"tags":["Organizations"],"summary":"Search organizations by name","description":"**Since v2.3.0** — Returns organizations whose name contains the query string (case-insensitive).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"search_2","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of matching organizations","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.search","description":"Search organizations by name"}],"x-since":"2.3.0","x-sunset":"2027-01-01"}},"/v2/orgs/mine":{"get":{"tags":["Organizations"],"summary":"List my organizations","description":"**Since v2.8.0** — Returns all organizations the authenticated user belongs to, with their role in each.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getMyOrgs_1","responses":{"200":{"description":"List of organizations with membership role","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.list","description":"List organizations the caller belongs to"}],"x-since":"2.8.0","x-sunset":"2027-01-01"}},"/v2/orgs/discover":{"get":{"tags":["Organizations"],"summary":"Discover organization by email","description":"**Since v2.3.0** — Finds the organization whose domain matches the given email address.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"discover_1","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization found (or empty if no match)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.discover","description":"Find an organization by email domain"}],"x-since":"2.3.0","x-sunset":"2027-01-01"}},"/v2/health":{"get":{"tags":["Administration"],"summary":"Health check (v2)","description":"**Since v2.2.0** — Returns service version info. Authenticated users get extended diagnostics.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getHealthStatus","parameters":[{"name":"X-TEST","in":"header","required":false,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"JSON with version info and optional diagnostics","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"x-intent":[{"name":"health.get","description":"Service health and version info"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/github/verify-access":{"get":{"tags":["Automation"],"summary":"Verify repository access (v2)","description":"**Since v2.4.2** — Deprecated — use GET /v3/github/verify-access instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"verifyAccess_2","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Access verification result","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.verify-access","description":"Verify GitHub repository access"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/github/actions/runs":{"get":{"tags":["Automation"],"summary":"Get latest workflow run (v2)","description":"**Since v2.4.2** — Deprecated — use GET /v3/github/actions/runs instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getLatestRun_2","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}}],"responses":{"200":{"description":"Latest workflow run status","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"No GitHub token or invalid repo URL","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"502":{"description":"GitHub API error","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"github-action.run.get","description":"Get the latest workflow run"}],"x-since":"2.4.2","x-sunset":"2027-01-01"}},"/v2/credits/transactions":{"get":{"tags":["Credits"],"summary":"Get Credits transactions (v2)","description":"**Since v7.44.0** — Returns the authenticated user's transaction history (paginated).","operationId":"getTransactions_2","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Transaction list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"credit.transaction.list.v2","description":"List the user's Credits transactions (v2)"}],"x-since":"7.44.0"}},"/v2/contracts/{contractId}":{"get":{"tags":["Contracts"],"summary":"Get a data contract (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/contracts/{contractId} instead. Retrieves a contract by ID in the specified format.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"read_9","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string"}},{"name":"subformat","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}}],"responses":{"200":{"description":"Contract in the requested format","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or version not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.get","description":"Get a data contract"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/contracts/maturity-level":{"get":{"tags":["Contracts"],"summary":"Measure contract maturity level (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/contracts/maturity-level instead. Returns a maturity level (1-5) for the specified data contract. Pass org (canonical) or orgSlug (legacy) to assess a contract stored in an organization's storage.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getMaturityLevel_3","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"org","in":"query","description":"Organization slug (canonical). Takes precedence over 'orgSlug' when both are present.","required":false,"schema":{"type":"string"}},{"name":"orgSlug","in":"query","description":"Deprecated — use 'org' instead. Organization slug (legacy parameter, kept for backward compatibility).","required":false,"deprecated":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Maturity assessment result","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"maturity.get","description":"Measure contract maturity level"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/contracts/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get contract lifecycle history (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/contracts/lifecycle instead. Requires Bearer JWT.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getContractLifecycle_2","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of lifecycle entries","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"lifecycle.contract.list","description":"Get contract lifecycle history"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/contracts/compare":{"get":{"tags":["Contracts"],"summary":"Compare two contracts (v2)","description":"**Since v2.2.0** — Deprecated — use GET /v3/contracts/compare instead. Compares two data contracts and returns a DiffResult. Pass org (canonical) or orgSlug (legacy) to compare contracts stored in an organization's storage.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"compareContracts_2","parameters":[{"name":"id1","in":"query","required":true,"schema":{"type":"string"}},{"name":"version1","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage1","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"id2","in":"query","required":true,"schema":{"type":"string"}},{"name":"version2","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage2","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"all"}},{"name":"org","in":"query","description":"Organization slug (canonical). Takes precedence over 'orgSlug' when both are present.","required":false,"schema":{"type":"string"}},{"name":"orgSlug","in":"query","description":"Deprecated — use 'org' instead. Organization slug (legacy parameter, kept for backward compatibility).","required":false,"deprecated":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"DiffResult JSON with differences and suggested version","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated or not a member of the organization","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found, or a contract or version not found on either side of the compare","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Comparison failure","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"contract.compare","description":"Compare two contracts"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/admin/validate":{"get":{"tags":["Administration"],"summary":"Force-validate a user (v2 admin)","description":"**Since v2.2.2** — Admin force-validates a user account by email, bypassing the validation code.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"forceValidateUser_1","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User successfully validated (or already validated)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.validate","description":"Force-validate a user account (admin)"}],"x-since":"2.2.2","x-sunset":"2027-01-01"}},"/v2/admin/users":{"get":{"tags":["Administration"],"summary":"List all users (v2 admin)","description":"**Since v2.2.0** — Returns all registered users with full details.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"listUsers_2","responses":{"200":{"description":"List of AdminUserResponse objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.list","description":"List all users (admin)"}],"x-since":"2.2.0","x-sunset":"2027-01-01"},"delete":{"tags":["Administration"],"summary":"Delete a user (v2 admin)","description":"**Since v2.2.0** — Deletes a user by email. User data is backed up before deletion.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"deleteUser_1","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User successfully deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.delete","description":"Delete a user by email (admin)"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/admin/users/active":{"get":{"tags":["Administration"],"summary":"List recently active users (v2 admin, experimental)","description":"**Since v2.2.3** — Returns users who made any API call within the specified time window. Defaults to the last 60 minutes.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"activeUsers_1","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":60}}],"responses":{"200":{"description":"List of AdminUserResponse objects for active users","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.user.list-active","description":"List recently active users (admin)"}],"x-since":"2.2.3","x-sunset":"2027-01-01"}},"/v2/admin/signup-requests":{"get":{"tags":["Administration"],"summary":"List signup requests","description":"**Since v2.7.0** — Returns a page of signup requests, optionally filtered by status (pending/approved/rejected).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"list_15","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}}],"responses":{"200":{"description":"Paged list","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"signup-request.list","description":"List signup requests"}],"x-since":"2.7.0","x-sunset":"2027-01-01"}},"/v2/admin/logs":{"get":{"tags":["Administration"],"summary":"Get activity logs (v2 admin) — DEPRECATED","description":"**Since v2.2.0** — Deprecated: use GET /v4/admin/logs. Retained for Workbench v1 (WB); the Workbench webapp (WB2) calls the v4 endpoint.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getActivityLogs_1","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"userId","in":"query","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of ActivityLog objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.log.list","description":"Get activity logs (admin)"}],"x-since":"2.2.0","x-sunset":"2027-01-01"}},"/v2/admin/invitation-history":{"get":{"tags":["Administration"],"summary":"List invite-driven signup history","description":"**Since v2.15.0** — Paginated (20 per page), searchable audit trail of every user who signed up with an invitation code. Each row carries the invitee email, the code used, the code type (personal | admin), the inviter email (em dash for admin codes), and the signup date. The optional 'search' parameter filters server-side across code, inviter email, and invitee email. Newest signups first. Accounts belonging to the Playwright E2E suites (e2e-test-*@actianlabs.com, e2e-admin@actianlabs.com, e2e-user@actianlabs.com) are HIDDEN by default; pass includeE2e=true to see them. The filter is applied server-side, so totalElements and totalPages describe the filtered set.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"list_16","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeE2e","in":"query","description":"Include accounts belonging to the Playwright E2E suites. Defaults to false, which hides e2e-test-*@actianlabs.com plus the fixed e2e-admin@ and e2e-user@ accounts from both the page and its count.","required":false,"schema":{"type":"boolean","default":false}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"Paged history","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"invitation-history.list","description":"List invite-driven signup history (admin)"}],"x-since":"2.15.0","x-sunset":"2027-01-01"}},"/v2/admin/emails":{"get":{"tags":["Administration"],"summary":"Get email logs (v2 admin)","description":"**Since v2.8.1** — Returns recent email delivery logs with recipient, subject, status, and timestamp.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getEmailLogs_1","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"JSON array of EmailLog objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.email-log.list","description":"Get email delivery logs (admin)"}],"x-since":"2.8.1","x-sunset":"2027-01-01"}},"/v2/admin/credits/balances":{"get":{"tags":["Credits"],"summary":"List all Credits balances (v2 admin)","description":"**Since v7.44.0** — Admin view of all users' Credits balances.","operationId":"getAllBalances_1","responses":{"200":{"description":"Balance list returned","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"admin.credit-balance.list.v2","description":"List all Credits balances (v2 admin)"}],"x-since":"7.44.0"}},"/v1/validate":{"get":{"tags":["Users"],"summary":"Validate email address","description":"**Since v1.0.0** — Activates a user account by verifying the 6-character code sent during registration. No authentication required.","operationId":"validateUser","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"validationCode","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User successfully validated (or already validated)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid validation code","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.validate","description":"Validate a user's email address with a code"}],"x-since":"1.0.0"}},"/v1/users/{id}":{"get":{"tags":["Users"],"summary":"Get user by ID","description":"**Since v1.0.0** — Retrieves user information by internal ID. Users can view their own data; admins can view any user.","operationId":"read_10","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"UserResponse with profile details and API key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Access denied (not own profile and not admin)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.get","description":"Get a user by ID"}],"x-since":"1.0.0"}},"/v1/users/profile":{"get":{"tags":["Users"],"summary":"Get user by email","description":"**Since v1.0.0** — Retrieves user information by email address. Users can view their own data; admins can view any user.","operationId":"readByEmail","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"UserResponse with profile details and API key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Access denied (not own profile and not admin)","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"user.get","description":"Get a user by email"}],"x-since":"1.0.0"}},"/v1/users/key":{"get":{"tags":["Users"],"summary":"Retrieve API key","description":"**Since v1.0.0** — Authenticates with email and password, returns the user's API key. Use this to recover a lost key or as a login equivalent.","operationId":"read_11","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"ApiKeyResponse containing the API key","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid email or password","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-since":"1.0.0"}},"/v1/tags/cloud":{"get":{"tags":["Tags"],"summary":"Get tag cloud (deprecated)","description":"**Since v1.0.0** — **Deprecated** — use `GET /v4/tags` instead. Returns all tags across contracts and products with their associated artifacts.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getTagCloud_1","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag cloud data","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"tag-cloud.get","description":"Get the tag cloud"}],"x-since":"1.0.0","x-sunset":"2027-01-01"}},"/v1/products/{productId}":{"get":{"tags":["Products"],"summary":"Get a data product","description":"**Since v1.0.0** — Retrieves a data product by ID. If no version is specified, the latest version is returned. Returns the full ODPS YAML content.","operationId":"read_12","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"ODPS YAML content as text","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Product not found or retrieval error","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"product.get","description":"Retrieve a data product by ID"}],"x-since":"1.0.0"}},"/v1/products/{productId}/verify-signature":{"get":{"tags":["Verification"],"summary":"Verify signature on a stored product (public)","description":"**Since v4.4.32** — Verifies the digital signature embedded in the specified product. No authentication required.","operationId":"verifyProduct_1","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"signature.verify","description":"Verify signature on a stored product"}],"x-since":"4.4.32"}},"/v1/products/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get product lifecycle history","description":"**Since v1.0.0** — Returns the lifecycle history of a data product, including status changes and deletion events.","operationId":"getProductLifecycle_3","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of lifecycle entries; each entry carries an `actor` object {userId, email, firstName, lastName} resolved from the recorded user (null when the user no longer exists)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"lifecycle.product.list","description":"Get product lifecycle history"}],"x-since":"1.0.0"}},"/v1/logs":{"get":{"tags":["Administration"],"summary":"Get activity logs (admin only, deprecated)","description":"**Since v1.0.0** — **Deprecated** — use `GET /v4/admin/logs` instead. Returns recent activity log entries. Use 'limit' to control count, 'userId' or 'email' to filter by user.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getActivityLogs_2","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"userId","in":"query","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of ActivityLog objects","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"User not found (when filtering by email)","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"activity-log.list","description":"Get recent activity logs (admin only)"}],"x-since":"1.0.0","x-sunset":"2027-01-01"}},"/v1/health":{"get":{"tags":["Administration"],"summary":"Health check","description":"**Since v1.0.0** — Returns service version info and status. Without authentication, returns basic version info. With authentication, admins get extended diagnostics (deployment time, database status, environment, classpath). Optional X-TEST header for diagnostic modes: pdf, richpdf (both render through PrettyPDF/JasperReports). The html mode was retired with the AsciiDoc renderer (#1128) and returns 400.","operationId":"getHealthStatus_1","parameters":[{"name":"X-TEST","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string","default":""}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"JSON with version info (all callers) and extended diagnostics (admins). The pdf and richpdf test modes return a PDF.","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password (only when headers are provided)","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"Error during diagnostic test mode","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"health.get","description":"Service health and version info"}],"x-since":"1.0.0"}},"/v1/github/verify-access":{"get":{"tags":["Automation"],"summary":"Verify repository access","description":"**Since v1.0.0** — Verifies that the GitHub token has sufficient permissions to access and modify the repository.","operationId":"verifyAccess_3","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"github-action.verify-access","description":"Verify GitHub repository access"}],"x-since":"1.0.0"}},"/v1/github/actions/runs":{"get":{"tags":["Automation"],"summary":"Get latest workflow run","description":"**Since v1.0.0** — Returns the status of the latest workflow run.","operationId":"getLatestRun_3","parameters":[{"name":"repoUrl","in":"query","required":false,"schema":{"type":"string"}},{"name":"workflowFile","in":"query","required":false,"schema":{"type":"string","default":"upload-data-products.yml"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"github-action.run.get","description":"Get the latest workflow run"}],"x-since":"1.0.0"}},"/v1/contracts/{contractId}":{"get":{"tags":["Contracts"],"summary":"Get a data contract","description":"**Since v1.0.0** — Retrieves a contract by ID in the specified format. If no version is given, the latest is returned.\n\n**Available formats (via `format` query parameter):**\n| format | Content-Type | Description |\n|--------|-------------|-------------|\n| `FULL` (default) | `application/x-yaml` | Complete ODCS YAML contract |\n| `HEADER` | `application/json` | Metadata only (id, version, name, domain, tenant, status) |\n| `DDL` | `text/plain` | SQL DDL (requires `subformat=PostgreSQL`) |\n| `PDF` | `application/pdf` | Basic PDF rendering of the contract |\n| `PrettyPDF` | `application/pdf` | Branded PDF with user's logo and custom PDF settings |\n","operationId":"read_13","parameters":[{"name":"contractId","in":"path","description":"Contract identifier (UUID)","required":true,"schema":{"type":"string"},"example":"34cae6d7-7648-38b2-8f66-8db79e1e2ce4"},{"name":"version","in":"query","description":"Semantic version (e.g. \"1.0.0\"). Omit for latest version.","required":false,"schema":{"type":"string"},"example":"1.0.0"},{"name":"format","in":"query","description":"Output format for the contract.","required":false,"schema":{"type":"string","enum":["FULL","HEADER","DDL","PDF","PrettyPDF"]}},{"name":"subformat","in":"query","description":"SQL dialect. Required when format=DDL. Currently only \"PostgreSQL\" is supported.","required":false,"schema":{"type":"string","enum":["PostgreSQL"]}},{"name":"storage","in":"query","description":"Storage location","required":false,"schema":{"type":"string","enum":["permanent","temporary"]}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract in the requested format (YAML, JSON, SQL text, or PDF bytes)","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unsupported subformat for DDL conversion","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or version not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.get","description":"Get a data contract"}],"x-since":"1.0.0"},"delete":{"tags":["Contracts"],"summary":"Delete a data contract (path-form)","description":"**Since v7.0.64** — Same as DELETE /v1/contracts but with the contractId in the URL path. `version` is required as a query parameter.","operationId":"deleteByPath_2","parameters":[{"name":"contractId","in":"path","description":"Contract identifier (UUID)","required":true,"schema":{"type":"string"},"example":"34cae6d7-7648-38b2-8f66-8db79e1e2ce4"},{"name":"version","in":"query","description":"Semantic version (e.g. \"1.0.0\"). Required.","required":true,"schema":{"type":"string"},"example":"1.0.0"},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}},{"name":"org","in":"query","description":"#1428 — organization slug. Omit for personal storage.","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"#1428 — organization UUID; takes precedence over `org`.","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contract deleted successfully","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Contract is referenced by one or more data products","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.delete","description":"Delete a data contract (path-form)"}],"x-since":"7.0.64"}},"/v1/contracts/{contractId}/verify-signature":{"get":{"tags":["Verification"],"summary":"Verify signature on a stored contract (public)","description":"**Since v4.4.32** — Verifies the digital signature embedded in the specified contract. No authentication required. The contract must be publicly accessible.","operationId":"verifyContract_1","parameters":[{"name":"contractId","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification result","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract not found","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"signature.verify","description":"Verify signature on a stored contract"}],"x-since":"4.4.32"}},"/v1/contracts/supported-databases":{"get":{"tags":["Contracts"],"summary":"List supported JDBC databases","description":"**Since v2.10.2** — Returns the list of database types supported for JDBC-based contract creation, with default port and schema info.","operationId":"getSupportedDatabases_2","responses":{"200":{"description":"List of supported database types","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.database.list","description":"List supported JDBC databases"}],"x-since":"2.10.2"}},"/v1/contracts/maturity-level":{"get":{"tags":["Contracts"],"summary":"Measure contract maturity level (deprecated)","description":"**Since v1.0.0** — **Deprecated** — use `GET /v4/contracts/maturity-level` instead. Returns a maturity level (1-5) and explanation for the specified data contract. If no version is given, the latest is used.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"getMaturityLevel_4","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON with maturityLevel (1-5), maturityLevelLabel, explanation, and nextLevelAdvice","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or version not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"maturity.get","description":"Measure contract maturity level"}],"x-since":"1.0.0","x-sunset":"2027-01-01"}},"/v1/contracts/lifecycle":{"get":{"tags":["Lifecycle"],"summary":"Get contract lifecycle history","description":"**Since v1.0.0** — Returns the lifecycle history of a data contract, including status changes, maturity assessments, and deletion events.","operationId":"getContractLifecycle_3","parameters":[{"name":"contractId","in":"query","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"JSON array of lifecycle entries; each entry carries an `actor` object {userId, email, firstName, lastName} resolved from the recorded user (null when the user no longer exists)","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"lifecycle.contract.list","description":"Get contract lifecycle history"}],"x-since":"1.0.0"}},"/v1/contracts/compare":{"get":{"tags":["Contracts"],"summary":"Compare two contracts","description":"**Since v1.0.0** — Compares two data contracts and returns a DiffResult with differences, semver impact levels (MAJOR/MINOR/PATCH), and a suggested next version.","operationId":"compareContracts_3","parameters":[{"name":"id1","in":"query","required":true,"schema":{"type":"string"}},{"name":"version1","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage1","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"id2","in":"query","required":true,"schema":{"type":"string"}},{"name":"version2","in":"query","required":false,"schema":{"type":"string"}},{"name":"storage2","in":"query","required":false,"schema":{"type":"string","default":"permanent"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"all"}},{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"DiffResult JSON with list of differences and suggested version","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Invalid API key or password","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Account not validated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Contract or version not found on either side of the compare","content":{"*/*":{"schema":{"type":"object"}}}},"500":{"description":"File error or comparison failure","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]},{"PasswordAuth":[]}],"x-intent":[{"name":"contract.compare","description":"Compare two contracts"}],"x-since":"1.0.0"}},"/signin":{"get":{"tags":["signin-controller"],"operationId":"showForm","parameters":[{"name":"return","in":"query","required":false,"schema":{"type":"string"}},{"name":"error","in":"query","required":false,"schema":{"type":"string"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/macos-installer":{"get":{"tags":["installer-controller"],"operationId":"macosInstaller","responses":{"200":{"description":"OK","content":{"application/x-sh":{"schema":{"type":"string"}}}}},"x-intent":[{"name":"installer.download","description":"Download the macOS MCP installer script"}]}},"/.well-known/openid-configuration":{"get":{"tags":["oidc-discovery-controller"],"operationId":"openidConfiguration","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/v4/users/me":{"delete":{"tags":["Users"],"summary":"Delete your own account","description":"**Since v9.48.0** — Deletes the authenticated caller's own account. Requires no admin privileges — a caller can only ever delete themselves, since the target is taken from the authenticated principal and not from a parameter.\n\nThe Keycloak user is cascaded, so the same address can register again. The caller's contracts and products on disk are **not** deleted. A caller who is the sole owner of an organization is refused with 409 — transfer ownership or delete the organization first.","operationId":"deleteSelf","parameters":[{"name":"X-API-KEY","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-USER-PASSWORD","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Account deleted","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Not authenticated","content":{"*/*":{"schema":{"type":"object"}}}},"409":{"description":"Caller is the sole owner of one or more organizations","content":{"*/*":{"schema":{"type":"object"}}}}},"x-intent":[{"name":"user.self.delete","description":"Delete your own account"}],"x-since":"9.48.0"}},"/v4/self-report/issues/{number}":{"delete":{"tags":["Self-Report"],"summary":"Retract a self-report","description":"**Since v9.114.4** — Closes the GitHub issue a self-report opened, comments saying who retracted it, and adds the `duplicate` label so provenance stays queryable. **Closes; never deletes** — closing is reversible, and the report's attachment blobs on the `used-for-self-reports-do-not-delete` branch are not touched.\n\nKeyed on the **issue number**, which the caller already holds: submit returns `issueUrl`. `reportId` is minted per call and never stored server-side, so it cannot address anything.\n\nAuthorisation: a platform admin may retract any self-report; any other signed-in caller may retract only a report they filed. Anonymous reports, and every report filed before this endpoint existed, carry no submitter marker and are admin-only. Bearer-only: an admin `X-API-KEY` is not accepted on /v4.\n\nReasons, on the same `{message, reason}` contract as submit:\n- `bearer_required` (403) — authenticated by something other than a Bearer JWT.\n- `not_a_self_report` (403) — the issue exists but is not one of this server's reports. The endpoint holds a repo-admin token; this is what stops it closing arbitrary issues.\n- `not_yours` (403) — a non-admin did not file it.\n- `not_found` (404) — no such issue in the configured repository.\n- `github_unreachable` / `github_rejected` (502), `github_auth` / `not_configured` (503) — as on submit.","operationId":"retract","parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"note","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Retracted, or already closed (idempotent).","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Not signed in.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"403":{"description":"Reason `bearer_required`, `not_a_self_report` or `not_yours`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"No such issue — reason `not_found`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"502":{"description":"GitHub-origin failure — reason `github_unreachable` or `github_rejected`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"503":{"description":"Server-side GitHub config error — reason `github_auth` or `not_configured`.","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}},"x-intent":[{"name":"self-report.retract","description":"Retract a self-report — closes its GitHub issue"}],"x-since":"9.114.4"}},"/v4/orgs/{slug}/messages/{messageId}":{"delete":{"tags":["Membership"],"summary":"Revoke a pending invitation (deprecated slug path)","description":"**Since v7.43.15** — Owner/admin revokes a PENDING invitation. Deprecated — use DELETE /v4/orgs/messages/{messageId} with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"revokeInvitationBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation revoked","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Message not found, not pending, or not an invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.43.15","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/members/{userId}":{"delete":{"tags":["Membership"],"summary":"Remove a member from the organization (deprecated slug path)","description":"**Since v7.11.0** — Admin/owner removes a member. Cannot remove the last owner. Deprecated — use DELETE /v4/orgs/members/{userId} with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeMemberBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Member removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot remove last owner","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/{slug}/members/me":{"delete":{"tags":["Membership"],"summary":"Leave the organization (deprecated slug path)","description":"**Since v7.11.0** — Authenticated user leaves the organization. Cannot leave if last owner. Deprecated — use DELETE /v4/orgs/members/me with org/orgId (#651).\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"leaveOrgBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Left organization","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot leave as last owner","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-since":"7.11.0","x-sunset":"2027-01-01"}},"/v4/orgs/service-accounts/{id}":{"delete":{"tags":["Service Accounts"],"summary":"Revoke a service account (org-ADMIN only)","description":"**Since v7.34.0** — Sets revoked_at. Token issuance fails immediately; outstanding tokens are rejected on their next call (revocation is re-checked per request).","operationId":"revoke","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Service account revoked","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Caller is not an ADMIN of the org","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or service account not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"serviceaccount.revoke","description":"Revoke a service account"}],"x-since":"7.34.0"}},"/v4/orgs/plugins/{id}":{"delete":{"tags":["Organization Plugins"],"summary":"Remove a plugin","description":"**Since v9.2.0** — Removes the registration, its activation state, and every member's saved settings for this plugin in this organization. Requires ADMIN+ role.","operationId":"remove","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role, or the plugin platform is off","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization or plugin not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.plugins.remove","description":"Remove a registered plugin"}],"x-since":"9.2.0"}},"/v4/orgs/messages/{messageId}":{"delete":{"tags":["Membership"],"summary":"Revoke a pending invitation","description":"**Since v7.43.15** — Owner/admin revokes a PENDING invitation so it stops appearing in GET /v4/orgs/messages. Distinct from invitee decline; keeps the row (status REVOKED) for an audit trail. Pass org (slug) or orgId (UUID). Requires ADMIN+ role.","operationId":"revokeInvitation","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Invitation revoked","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId, message not found, not pending, or not an invitation","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.invitation.revoke","description":"Revoke a pending organization invitation"}],"x-since":"7.43.15"}},"/v4/orgs/members/{userId}":{"delete":{"tags":["Membership"],"summary":"Remove a member from the organization","description":"**Since v7.26.0** — Admin/owner removes a member. Cannot remove the last owner. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"removeMember","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Member removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or cannot remove last owner","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.remove","description":"Remove a member from the organization"}],"x-since":"7.26.0"}},"/v4/orgs/members/me":{"delete":{"tags":["Membership"],"summary":"Leave the organization","description":"**Since v7.26.0** — Authenticated user leaves the organization. Cannot leave if last owner. Pass org (slug) or orgId (UUID) to select the organization.","operationId":"leaveOrg","parameters":[{"name":"org","in":"query","description":"Organization slug","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization UUID (takes precedence over org)","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Left organization","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Missing org/orgId parameter or cannot leave as last owner","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.leave","description":"Leave the organization"}],"x-since":"7.26.0"}},"/v4/orgs/agent-providers/{id}":{"delete":{"tags":["Organization Agent Providers"],"summary":"Remove an agent provider","description":"**Since v8.6.0** — Removes a registered agent provider. Pass org (slug) or orgId (UUID). Requires ADMIN+ role.","operationId":"remove_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"org","in":"query","required":false,"schema":{"type":"string"}},{"name":"orgId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Removed","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.agents.providers.remove","description":"Remove an agent provider"}],"x-since":"8.6.0"}},"/v4/admin/blocked-domains/{id}":{"delete":{"tags":["Administration"],"summary":"Unblock a domain","description":"**Since v7.13.0** — Removes an email domain from the blocklist.","operationId":"unblockDomain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain unblocked successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain not found","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"BearerAuth":[]}],"x-intent":[{"name":"blocked-domain.delete","description":"Remove an email domain from the blocklist"}],"x-since":"7.13.0"}},"/v2/orgs/{slug}/members/{userId}":{"delete":{"tags":["Membership"],"summary":"Remove a member from the organization","description":"**Since v2.5.0** — Admin/owner removes a member. Cannot remove the last owner.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"removeMember_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Member removed","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot remove last owner","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Insufficient role","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.remove","description":"Remove a member from the organization"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/orgs/{slug}/members/me":{"delete":{"tags":["Membership"],"summary":"Leave the organization","description":"**Since v2.5.0** — Authenticated user leaves the organization. Cannot leave if last owner.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"leaveOrg_1","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Left organization","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot leave as last owner","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Organization not found","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"org.member.leave","description":"Leave the organization"}],"x-since":"2.5.0","x-sunset":"2027-01-01"}},"/v2/admin/blocked-domains/{id}":{"delete":{"tags":["Administration"],"summary":"Unblock a domain","description":"**Since v2.6.0** — Removes an email domain from the blocklist.\n\n_Sunset: 2027-01-01 — this endpoint will be removed at the v8 major bump._","operationId":"unblockDomain_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain unblocked successfully","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Domain not found","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid JWT","content":{"*/*":{"schema":{"type":"object"}}}},"403":{"description":"Admin privileges required","content":{"*/*":{"schema":{"type":"object"}}}}},"deprecated":true,"security":[{"BearerAuth":[]}],"x-intent":[{"name":"blocked-domain.delete","description":"Remove an email domain from the blocklist"}],"x-since":"2.6.0","x-sunset":"2027-01-01"}}},"components":{"schemas":{"GitHubDefaultsRequest":{"type":"object","description":"Request body for setting GitHub integration defaults","properties":{"defaultRepository":{"type":"string","description":"Default GitHub repository URL for publishing","example":"https://github.com/acme/data-contracts"},"defaultBranch":{"type":"string","description":"Default Git branch for publishing (e.g. main, dev, or any custom branch name)","example":"main"},"defaultCommitMessage":{"type":"string","description":"Default commit message template. Supports placeholders: {{name}}, {{version}}, {{type}}, {{id}}, {{timestamp}}","example":"Update {{type}} {{name}} v{{version}}"},"autoPublish":{"type":"boolean","description":"Automatically publish to GitHub when a contract or product is created/updated","example":false}}},"LifecycleUpdateRequest":{"type":"object","description":"Request body for editing a lifecycle entry comment","properties":{"comment":{"type":"string","description":"The new comment text","example":"Reviewed and approved by data governance team."}}},"TransferOwnershipRequest":{"type":"object","description":"Request body for transferring organization ownership to another member.","properties":{"newOwnerUserId":{"type":"integer","format":"int64","description":"Internal user ID of the new owner. Must be an existing member of the organization.","example":42},"newOwnerEmail":{"type":"string","description":"Email address of the new owner. Must be an existing member of the organization.","example":"newowner@company.com"}}},"DiagnosticsReportRequest":{"type":"object","description":"Inbound diagnostics report from front end","properties":{"type":{"type":"string","description":"Issue type","example":"api_error"},"sequenceNumber":{"type":"integer","format":"int32","description":"Session-local sequence number for ordering","example":3},"timestamp":{"type":"string","description":"Client-side ISO-8601 timestamp","example":"2026-02-27T12:00:00.000Z"},"appVersion":{"type":"string","description":"Workbench app version","example":"0.12.22"},"serverVersion":{"type":"string","description":"Libot API version reported by front end","example":"3.1.0"},"coreLibraryVersion":{"type":"string","description":"Core library version","example":"3.1.16"},"userEmail":{"type":"string","description":"User email (self-reported)","example":"user@example.com"},"errorMessage":{"type":"string","description":"Error message","example":"HTTP 500 Internal Server Error"},"currentUrl":{"type":"string","description":"Page URL where error occurred"},"userAgent":{"type":"string","description":"Browser user agent"},"userComment":{"type":"string","description":"User-provided comment"},"reportType":{"type":"string","description":"automatic or user","example":"automatic"},"payload":{"description":"Full diagnostic payload (JSON object) for Playwright replay"},"provenance":{"type":"string","description":"Client provenance (api, webapp, iosapp)","example":"webapp"},"app":{"type":"string","description":"Application name (bitol, workbench, badge, jyo)","example":"workbench"}}},"JdbcConnectionRequest":{"type":"object","description":"JDBC database connection parameters. Sent as a JSON request body to keep credentials out of URLs.","properties":{"dbType":{"type":"string","description":"Database vendor type","example":"postgresql"},"dbHost":{"type":"string","description":"Database hostname or IP","example":"localhost"},"dbPort":{"type":"integer","format":"int32","description":"Database port (-1 for vendor default)","example":5432},"dbName":{"type":"string","description":"Database name","example":"mydb"},"dbSchema":{"type":"string","description":"Schema name (null for vendor default)","example":"public"},"dbUsername":{"type":"string","description":"Database username","example":"admin"},"dbPassword":{"type":"string","description":"Database password","example":"secret"},"dataSource":{"type":"string","description":"Optional reference to a reusable named data source (#718). When set on a contract-server binding, the inline connection fields are ignored and the connection is resolved from the data-source registry within the caller's scope.","example":"warehouse-prod"}},"required":["dbHost","dbName","dbType"]},"BadgeTemplateRequest":{"type":"object","description":"Badge template configuration","properties":{"id":{"type":"string","description":"Badge id; create only, ignored on update","example":"podemaster_platinum"},"name":{"type":"string","description":"Display name","example":"Podemaster"},"tier":{"type":"string","description":"Tier; null for untiered badges","example":"Bronze"},"description":{"type":"string","description":"Short catalog description","example":"Created 5 artifacts"},"criteriaNarrative":{"type":"string","description":"Plain-language statement of what earns this"},"criteriaType":{"type":"string","description":"count | multi | days_since_joined | leaderboard_rank"},"criteriaValue":{"type":"string","description":"JSON matching the criteria type","example":{"threshold":5}},"criteriaSource":{"type":"string","description":"The attribution rule — where the count comes from"},"imagePath":{"type":"string","description":"Classpath-relative art","example":"badges/podemaster_bronze.png"},"enabled":{"type":"boolean","description":"Whether the badge appears in the catalog and is awarded"},"sortOrder":{"type":"integer","format":"int32","description":"Catalog render order"}}},"AdminUserResponse":{"type":"object","description":"Complete user record (all fields except password hash). Only returned by admin endpoints.","properties":{"id":{"type":"integer","format":"int64","example":42},"email":{"type":"string","example":"user@company.com"},"firstName":{"type":"string","example":"Jane"},"lastName":{"type":"string","example":"Smith"},"company":{"type":"string","example":"Acme Corp"},"dob":{"type":"string","format":"date","example":"1990-05-15"},"comment":{"type":"string","example":"Data engineering team lead."},"apiKey":{"type":"string","example":"68e92a92-0d15-4d17-aad6-9fecb07dd78a"},"validationCode":{"type":"string","description":"6-character alphanumeric code","example":"ABC123"},"validationCodeGeneratedAt":{"type":"string","format":"date-time","example":"2026-02-07T10:30:00"},"validatedAt":{"type":"string","format":"date-time","example":"2026-02-07T10:35:00"},"admin":{"type":"boolean","example":false},"createdAt":{"type":"string","format":"date-time","example":"2026-02-07T10:30:00"},"updatedAt":{"type":"string","format":"date-time","example":"2026-02-07T10:35:00"},"resendCount":{"type":"integer","format":"int32","description":"Number of validation email resends","example":0},"code":{"type":"string","description":"Tracking or promotional code","example":"PROMO2026"},"hasGithubToken":{"type":"boolean","description":"Whether the user has a GitHub token configured (token itself is never exposed)","example":true},"lastActivity":{"type":"string","format":"date-time","description":"Timestamp of the user's most recent API activity","example":"2026-02-13T08:15:00"},"standardChannel":{"type":"string","description":"The user's standard-version channel, as stored. Normally Production, Previous or Experimental; a value outside the current enum — a channel retired in an earlier release, say — is returned verbatim rather than coerced, and null means the column itself is null.","example":"Production"},"validated":{"type":"boolean"}}},"UserUpdateRequest":{"type":"object","description":"Profile update fields. Authentication is via X-API-KEY and X-USER-PASSWORD headers (no password in body).","properties":{"firstName":{"type":"string","description":"Must not contain \"<<\", \">>\", or the word \"name\".","example":"Jean-Georges"},"lastName":{"type":"string","description":"Must not contain \"<<\", \">>\", or the word \"name\".","example":"Perrin"},"company":{"type":"string","description":"Must not contain \"<<\", \">>\" or \"your company\".","example":"Bitol"},"dob":{"type":"string","format":"date","description":"Date of birth (YYYY-MM-DD)","example":"1990-01-01"},"comment":{"type":"string","description":"Must not contain \"<<\" or \">>\".","example":"Updated profile."},"githubToken":{"type":"string","description":"GitHub Personal Access Token for publishing contracts to GitHub. The token is stored securely and never returned in API responses.","example":"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"},"autoSign":{"type":"boolean","description":"When true, contracts and products are automatically signed before GitHub publish.","example":false}}},"PasswordChangeRequest":{"type":"object","description":"Request body for changing a user's password","properties":{"currentPassword":{"type":"string","description":"Current password. Required for non-admin callers; omit when admin changes another user's password.","example":"oldSecurePassword123"},"newPassword":{"type":"string","description":"New password. Must be at least 8 characters.","example":"newSecurePassword456"}},"required":["newPassword"]},"V2VerifyRequest":{"type":"object","description":"Request body for v2 email verification","properties":{"email":{"type":"string","description":"Email address of the account to verify","example":"user@company.com"},"code":{"type":"string","description":"6-character verification code sent via email","example":"A1B2C3"}},"required":["code","email"]},"UserCreateRequest":{"type":"object","description":"Request body for creating a new user account","properties":{"email":{"type":"string","description":"Must be a valid email format. Must not contain a `+` character. Personal email domains are blocked: gmail.com, yahoo.com, hotmail.com, outlook.com, aol.com, protonmail.com, icloud.com, mail.com, yandex.com, live.com, msn.com, gmx.com, zoho.com, tutanota.com, pm.me.","example":"user@company.com"},"firstName":{"type":"string","description":"Must not contain \"<<\", \">>\", or the word \"name\".","example":"Jane"},"lastName":{"type":"string","description":"Must not contain \"<<\", \">>\", or the word \"name\".","example":"Smith"},"company":{"type":"string","description":"Must not contain \"<<\", \">>\" or \"your company\".","example":"Acme Corp"},"dob":{"type":"string","format":"date","description":"Date of birth (YYYY-MM-DD)","example":"1990-05-15"},"comment":{"type":"string","description":"Must not contain \"<<\" or \">>\".","example":"Data engineering team lead."},"password":{"type":"string","description":"Optional. If omitted, the service generates a password.","example":"mySecurePassword123"},"code":{"type":"string","description":"Optional tracking code (e.g. promotional or referral code).","example":"PROMO2026"},"invitationCode":{"type":"string","description":"Optional Grand Opening invitation code. If set, signup is allowed even when bitol.signup.requires-code is true. Validated case-insensitively against personal and admin codes.","example":"bluedata42"}},"required":["email"]},"TransferItem":{"type":"object","description":"A single artifact to transfer from personal to org storage","properties":{"type":{"type":"string","description":"Artifact type","enum":["contract","product"],"example":"contract"},"id":{"type":"string","description":"Artifact ID (UUID)","example":"34cae6d7-7648-38b2-8f66-8db79e1e2ce4"},"version":{"type":"string","description":"Semantic version","example":"1.0.0"}}},"CreateRequest":{"type":"object","description":"Service-account creation request","properties":{"name":{"type":"string"},"description":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"uniqueItems":true}}},"PluginRegisterRequest":{"type":"object","description":"Register a plugin for an organization by manifest URL","properties":{"manifestUrl":{"type":"string","description":"URL of the plugin manifest (JSON)","example":"https://ext.example.com/md-publisher/manifest.json"},"authToken":{"type":"string","description":"Optional bearer token sent to the plugin endpoint; stored encrypted, never returned"}}},"Artifact":{"type":"object","description":"The artifact a contribution was invoked on","properties":{"kind":{"type":"string","description":"contract or product","example":"product"},"id":{"type":"string","description":"Artifact UUID"},"version":{"type":"string","description":"Artifact version; omit for the latest"}}},"PluginInvokeRequest":{"type":"object","description":"Invoke a plugin contribution","properties":{"pluginId":{"type":"string","description":"Reverse-DNS plugin identifier","example":"com.hcl.docs.md-publisher"},"target":{"type":"string","description":"The contribution's target","example":"product.row-menu"},"artifact":{"$ref":"#/components/schemas/Artifact","description":"The artifact the user clicked"},"message":{"type":"string","description":"Message text; defaults to the contribution's label on the first turn"},"contextId":{"type":"string","description":"A2A conversation context to continue (conversational contributions)"}}},"AgentAttachmentDto":{"type":"object","description":"An editor artifact attached to an agent invocation","properties":{"kind":{"type":"string","description":"Artifact kind. Both vocabularies are accepted, permanently and case-insensitively (#1178): the original wire spelling 'contract'/'product', and the standard's own 'DataContract'/'DataProduct'. Neither is deprecated.","enum":["contract","product","DataContract","DataProduct"],"example":"DataContract"},"id":{"type":"string","description":"Artifact id (optional)"},"version":{"type":"string","description":"Artifact version (optional)"},"name":{"type":"string","description":"Human-readable artifact name (optional)"},"format":{"type":"string","description":"Content format. Both vocabularies are accepted, permanently and case-insensitively (#1178): the original 'odcs-yaml'/'odps-yaml', and the registered media types 'application/odcs+yaml'/'application/odps+yaml'. A media type may carry parameters, which are ignored — 'application/odcs+yaml;version=3.1.0' and 'application/odcs+yaml' are the same format.","enum":["odcs-yaml","odps-yaml","application/odcs+yaml","application/odps+yaml"],"example":"application/odcs+yaml;version=3.1.0"},"content":{"type":"string","description":"The artifact content (YAML)"},"role":{"type":"string","description":"Role of this attachment relative to the open artifact","enum":["primary","input","output"],"example":"primary"}}},"AgentInvokeRequest":{"type":"object","description":"Send a message to an imported A2A agent via the server-side proxy","properties":{"cardUrl":{"type":"string","description":"cardUrl of the target agent, as returned by GET /v4/orgs/agents","example":"https://quokka.actianlabs.com/agents/smalltalk/.well-known/agent-card.json"},"message":{"type":"string","description":"The user's message text"},"contextId":{"type":"string","description":"Optional A2A contextId to continue a conversation"},"attachments":{"type":"array","description":"Open editor artifact(s) to attach as agent context (svc#985)","items":{"$ref":"#/components/schemas/AgentAttachmentDto"}}}},"AgentProviderRequest":{"type":"object","description":"Register an A2A agent provider (registry URL) for an organization","properties":{"url":{"type":"string","description":"A2A registry discovery URL","example":"https://quokka.actianlabs.com/agents"},"label":{"type":"string","description":"Optional display label","example":"Quokka"},"authToken":{"type":"string","description":"Optional bearer token sent to the provider; stored encrypted, never returned"}}},"CoachInteractionRequest":{"type":"object","description":"One pseudonymous Governance Coach interaction record","properties":{"pseudonymId":{"type":"string","description":"Client-generated random UUID v4 — the only correlation key"},"questionText":{"type":"string","description":"The user's question, verbatim (max 8000 chars)"},"answerText":{"type":"string","description":"The coach's full answer (max 32000 chars)"},"retrievedPaths":{"type":"array","description":"Schema paths / corpus keys the RAG retrieval injected (max 8, 256 chars each)","items":{"type":"string"}},"maturityGaps":{"type":"array","description":"Failing maturity criterion ids at ask-time (max 32, 256 chars each)","items":{"type":"string"}},"artifactKind":{"type":"string","description":"Artifact kind. Both vocabularies are accepted, permanently and case-insensitively (#1178): 'contract'/'product' and 'DataContract'/'DataProduct'. Anything else is a 400 whose message lists all four.","enum":["contract","product","DataContract","DataProduct"],"example":"DataContract"},"section":{"type":"string","description":"Editor section active at ask-time (max 128 chars)","example":"fundamentals"},"appVersion":{"type":"string","description":"Client APP_VERSION (max 128 chars)","example":"2.11.0"},"source":{"type":"string","description":"Source application (max 128 chars)","example":"tutor"},"artifactHash":{"type":"string","description":"#1198 — client-computed opaque key, hash(artifactId + pseudonymSalt), where the salt is the client's own pseudonym secret. Stable for one user on one artifact, so 'every question asked while working on this contract' becomes derivable; not reversible to an artifact id and not comparable across users, so the no-re-identification property is preserved. Optional (max 256 chars)."},"sessionId":{"type":"string","description":"#1198 — client-generated UUID, new per coach session, grouping the turns of one conversation so a follow-up question is interpretable alongside the turns that preceded it. Opaque to the server. Optional (max 128 chars)."}},"required":["answerText","artifactKind","pseudonymId","questionText"]},"CrawlImportRequest":{"type":"object","properties":{"repoUrl":{"type":"string"},"branch":{"type":"string"},"folders":{"type":"array","items":{"type":"string"}}}},"SseEmitter":{"type":"object","properties":{"timeout":{"type":"integer","format":"int64"}}},"ImportReport":{"type":"object","properties":{"imported":{"type":"array","items":{"type":"string"}},"skipped":{"type":"array","items":{"type":"string"}},"sourceOrgSlug":{"type":"string"}}},"ContractTestRequest":{"type":"object","description":"Data-contract test-execution request","properties":{"server":{"type":"string","description":"The servers[].server name declared in the contract to test against","example":"production"},"version":{"type":"string","description":"Optional contract version to pin; defaults to the latest","example":"1.0.0"}},"required":["server"]},"ContactSyncRequest":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"},"sourcePage":{"type":"string"},"sourceSystem":{"type":"string"},"formName":{"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"submittedAt":{"type":"string"}}},"CommentRequest":{"type":"object","description":"Request body for creating or editing a comment","properties":{"orgId":{"type":"string","description":"Organization UUID (priority over org slug)","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"org":{"type":"string","description":"Organization slug (alternative to orgId)","example":"oplo-llc"},"artifactKind":{"type":"string","description":"Artifact kind: DataContract or DataProduct","example":"DataContract","minLength":1},"artifactId":{"type":"string","description":"Artifact UUID","example":"f47ac10b-58cc-4372-a567-0e02b2c3d479","minLength":1},"artifactVersion":{"type":"string","description":"Artifact version (optional)","example":"v1.0.0"},"anchorType":{"type":"string","description":"Anchor granularity: ARTIFACT, SECTION, or ELEMENT","example":"SECTION"},"anchorSection":{"type":"string","description":"Top-level YAML section name","example":"schema"},"anchorElementId":{"type":"string","description":"Element id within the section"},"targetHandle":{"type":"string","description":"For anchorType=PROFILE: the handle of the person whose profile this message is left on (#1217). Ignored for artifact comments.","example":"jean-georges.perrin"},"parentId":{"type":"string","description":"Parent comment UUID for replies; omit for top-level comments"},"body":{"type":"string","description":"Comment body in Markdown with @[email] mentions","example":"The customer_id field needs a description. @[alice@example.com]! can you add one?","minLength":1}},"required":["artifactId","artifactKind","body"]},"RefreshReport":{"type":"object","properties":{"scope":{"type":"string"},"dryRun":{"type":"boolean"},"examined":{"type":"integer","format":"int32"},"refreshed":{"type":"integer","format":"int32"},"unchanged":{"type":"integer","format":"int32"},"skipped":{"type":"array","items":{"type":"string"}}}},"AiSuggestRequest":{"type":"object","description":"AI text-suggestion request","properties":{"field":{"type":"string","description":"Field to suggest text for; defaults to description","example":"description"},"context":{"type":"string","description":"Surrounding artifact context the model grounds the suggestion in","example":"Contract Name: Sales\nDomain: seller\nSchemas: tbl_sales"},"currentValue":{"type":"string","description":"Existing text to improve; empty for a fresh suggestion"}}},"CreditGrant":{"type":"object","description":"Credit grant riding with the message","properties":{"amount":{"type":"integer","format":"int32","description":"Credits to grant; must be a positive integer","example":500},"note":{"type":"string","description":"Note recorded on the credit transaction; defaults to the message subject","example":"Welcome bonus"}},"required":["amount"]},"UserMessageRequest":{"type":"object","description":"Admin message to a user, with an optional credit grant (#1398)","properties":{"subject":{"type":"string","description":"Subject line; also the email subject after the [Workbench] prefix","example":"Welcome aboard"},"body":{"type":"string","description":"Message body, plain text","example":"Thanks for joining. Here are 500 Credits to get started."},"creditGrant":{"$ref":"#/components/schemas/CreditGrant","description":"Optional credit grant applied in the same transaction as the message"}},"required":["body","subject"]},"TestRunMuteRequest":{"type":"object","description":"Mute alerts on one test suite; the reason is required and recorded","properties":{"app":{"type":"string","description":"The diagnostics `app` of the suite's runs","example":"wb2"},"process":{"type":"string","description":"The suite's `source.process`","example":"e2e"},"provenance":{"type":"string","description":"The runs' provenance; omit for runs posted without one","example":"admin-invitations"},"reason":{"type":"string","description":"Why this suite's alerts are being silenced","example":"Known failure, fix tracked in WB3#1612"}},"required":["app","process","reason"]},"TestRunSuiteMute":{"type":"object","description":"A recorded decision to stop alerting on one test suite","properties":{"id":{"type":"string","format":"uuid","description":"Row UUID"},"suiteKey":{"type":"string","description":"The suite, as `app / process [provenance]`","example":"wb2 / e2e [admin-invitations]"},"app":{"type":"string","description":"The diagnostics `app` of the suite's runs","example":"wb2"},"process":{"type":"string","description":"The suite's `source.process`","example":"e2e"},"provenance":{"type":"string","description":"The runs' provenance","example":"admin-invitations"},"reason":{"type":"string","description":"Why alerts on this suite are silenced"},"mutedBy":{"type":"string","description":"Email of the admin who muted it"},"mutedAt":{"type":"string","format":"date-time","description":"When it was muted"},"unmutedBy":{"type":"string","description":"Email of the admin who unmuted it"},"unmutedAt":{"type":"string","format":"date-time","description":"When it was unmuted; null while the mute is active"},"active":{"type":"boolean","description":"True while the mute is in force"}}},"ResetPasswordRequest":{"type":"object","description":"Request body for completing a password reset with verification code","properties":{"email":{"type":"string","description":"Email address of the account.","example":"user@company.com"},"code":{"type":"string","description":"6-character reset code received via email.","example":"A3F2B1"},"newPassword":{"type":"string","description":"New password. Must be at least 8 characters.","example":"newSecurePassword456"}},"required":["code","email","newPassword"]},"ForgotPasswordRequest":{"type":"object","description":"Request body for initiating a password reset","properties":{"email":{"type":"string","description":"Email address of the account to reset.","example":"user@company.com"}},"required":["email"]},"Rfc7591RegistrationRequest":{"type":"object","properties":{"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string"},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"}}},"UserResponse":{"type":"object","description":"User profile information returned to non-admin callers","properties":{"email":{"type":"string","example":"user@company.com"},"firstName":{"type":"string","example":"Jane"},"lastName":{"type":"string","example":"Smith"},"company":{"type":"string","example":"Acme Corp"},"dob":{"type":"string","format":"date","example":"1990-05-15"},"comment":{"type":"string","example":"Data engineering team lead."},"createdAt":{"type":"string","format":"date-time","example":"2026-02-07T10:30:00"},"updatedAt":{"type":"string","format":"date-time","example":"2026-02-07T10:30:00"},"apiKey":{"type":"string","description":"API key for authenticating subsequent requests","example":"68e92a92-0d15-4d17-aad6-9fecb07dd78a"},"isAdmin":{"type":"boolean","description":"Only present when true. Omitted for non-admin users.","example":true},"hasGithubToken":{"type":"boolean","description":"Whether the user has a GitHub token configured","example":false},"showExperimentalSettings":{"type":"boolean","description":"Whether experimental/beta settings should be rendered for this user","example":true},"invitationCode":{"type":"string","description":"Personal invitation code (Grand Opening). Lazy-generated on first profile read; lowercase, matches ^[a-z]+[0-9]+$.","example":"bluedata42"},"invitationsUsedThisWeek":{"type":"integer","format":"int32","description":"Personal invitation codes used this week. Resets every Monday 00:00 EST.","example":0},"invitationBudget":{"type":"integer","format":"int32","description":"Personal invitations allowed per week.","example":5},"inviteDigestOptOut":{"type":"boolean","description":"When true, the user has opted out of the weekly invite digest email. Default false (opted in).","example":false},"linkedinUrl":{"type":"string","description":"#1214 — LinkedIn profile URL. https:// only.","example":"https://www.linkedin.com/in/jgperrin"},"githubUrl":{"type":"string","description":"#1214 — GitHub profile URL. https:// only.","example":"https://github.com/jgperrin"},"githubUrlVerified":{"type":"boolean"},"websiteUrl":{"type":"string","description":"#1214 — personal or company website. https:// only.","example":"https://jgp.ai"},"headline":{"type":"string","description":"#1214 — one-line professional headline, at most 160 characters.","example":"Data contracts, data products, and the standards behind them."},"bio":{"type":"string","description":"#1214 — free-text biography, at most 500 characters. Stored raw and escaped at render time. Distinct from `comment`, which is an internal admin note and is never published.","example":"Chief innovation officer, author, and long-time data engineer."},"handle":{"type":"string","description":"#1213 — the public identity a profile URL hangs off, `firstname.lastname`. Null when the account has no name to seed one from; the person is prompted to choose one, and nothing else depends on it being present.","example":"jean-georges.perrin"},"publicProfile":{"type":"boolean","description":"#1212 — whether this person appears on cross-user surfaces (the leaderboard, a public profile page). False for every account that existed before the flag shipped: the column is NULL for them and NULL reads as false. New signups get true.","example":true},"publicCompany":{"type":"boolean","description":"#1212 — whether the free-text `company` string is shown on this person's public profile. True by default. Distinct from an organization's own `publicCompany`.","example":true},"standardChannel":{"type":"string","description":"Standard-version channel for this user's PERSONAL workspace (#1091): Production (the current approved release, and the default), Previous (the newest approved release older than it) or Experimental (the newest bundled edition, may be an unapproved draft). An organization's own channel governs artifacts created in that organization's workspace.","enum":["Production","Previous","Experimental"],"example":"Production"},"availableChannels":{"type":"array","description":"Every standard-version channel this user may select, in display order. Derived from the enum, so a client should render this list rather than hard-code it. Present on the profile endpoints only.","example":["Production","Previous","Experimental"],"items":{"type":"string"}}}},"DiagnosticsResolveRequest":{"type":"object","description":"Request to resolve or reopen a diagnostics report","properties":{"resolved":{"type":"boolean","description":"true to resolve, false to reopen","example":true},"email":{"type":"string","description":"Admin email performing the action","example":"admin@example.com"},"comment":{"type":"string","description":"Optional comment for the resolution log"}}},"BadgeAwardResponse":{"type":"object","description":"A badge earned by the caller","properties":{"id":{"type":"string","description":"Award id — addresses this specific earning"},"badgeId":{"type":"string","description":"Catalog badge id","example":"podemaster_bronze"},"awardedAt":{"type":"string","format":"date-time","description":"When it was earned"},"imageUrl":{"type":"string","description":"Where the badge art is served from","example":"/v4/badges/podemaster_bronze/image"},"periodStart":{"type":"string","description":"Recurring period this award belongs to; 'once' for one-time badges","example":"once"},"seenAt":{"type":"string","format":"date-time","description":"When the user acknowledged it; null means the client should still celebrate it"}}},"ProfileRank":{"type":"object","description":"A rank within a named organization","properties":{"rank":{"type":"integer","format":"int32","description":"Dense, 1-based rank","example":3},"orgName":{"type":"string","description":"The organization ranked within","example":"Actian"},"orgSlug":{"type":"string","description":"That organization's slug","example":"actian"}}},"PublicOrgSummary":{"type":"object","description":"An organization named on a public profile","properties":{"name":{"type":"string","example":"Actian"},"slug":{"type":"string","example":"actian"}}},"PublicProfileResponse":{"type":"object","description":"A user's public profile, as another signed-in Workbench user sees it","properties":{"handle":{"type":"string","description":"The subject's public handle","example":"jean-georges.perrin"},"displayName":{"type":"string","description":"Display name — never the email address","example":"Jean-Georges Perrin"},"company":{"type":"string","description":"The subject's company. Absent when they have turned `publicCompany` off, or have not set one.","example":"Actian"},"headline":{"type":"string","description":"One-line headline (#1214)"},"bio":{"type":"string","description":"Free-text biography (#1214). Raw text — escape it at render time."},"linkedinUrl":{"type":"string","description":"LinkedIn profile URL (#1214)"},"githubUrl":{"type":"string","description":"GitHub profile URL (#1214)"},"githubUrlVerified":{"type":"boolean","description":"Whether `githubUrl` was derived from a linked GitHub identity rather than typed by hand (#1287). Explicit on the wire so a client renders provenance rather than inferring it from the URL's shape.","example":true},"websiteUrl":{"type":"string","description":"Personal or company website (#1214)"},"gravatarHash":{"type":"string","description":"Hex SHA-256 of the subject's lowercased, trimmed account email, for building a Gravatar URL client-side. **Derived from the email address**: anyone already holding that address can confirm a match against this hash. That is inherent to Gravatar, and is why it is emitted only for a profile its owner has made public. SHA-256, not MD5 — Gravatar moved, and an MD5 hash resolves to nothing.","example":"205e460b479e2e5b48aec07710c08d50"},"memberSince":{"type":"string","format":"date-time","description":"When the subject joined"},"organizations":{"type":"array","description":"The subject's organizations, filtered to those with `publicCompany` (#1218). Never a member list — an org names itself here, it does not enumerate its people.","items":{"$ref":"#/components/schemas/PublicOrgSummary"}},"badges":{"type":"array","description":"Badges the subject has earned","items":{"$ref":"#/components/schemas/BadgeAwardResponse"}},"credits":{"type":"integer","format":"int64","description":"Credits the subject has earned all-time — contribution, not balance","example":4820},"rank":{"$ref":"#/components/schemas/ProfileRank","description":"The subject's rank within an organization the viewer also belongs to. Absent when the viewer and the subject share no public organization, and absent when they share more than one — there is no basis to choose between them, and picking one would make the same person's rank differ per viewer with nothing saying why. It is never a global rank. That is this surface's own choice, not a consequence of the leaderboard's permissions — `scope=global` is open to any authenticated caller (#1540), and it anonymises. A profile page names a specific person, so putting a cross-tenant rank on it would say something the anonymised board deliberately does not."},"contractCount":{"type":"integer","format":"int32","description":"Data contracts the subject owns, summed over their personal workspace plus every organization the **viewer** is also a member of (#1236). Read `countScope` and `countedOrganizations` to state what this figure covers — the same profile legitimately shows a different number to a different viewer. Bounded — see PublicProfileService for the cap and why it exists.","example":12},"productCount":{"type":"integer","format":"int32","description":"Data products the subject owns, over the same workspaces as `contractCount` (#1236). Bounded.","example":3},"countScope":{"type":"string","description":"What `contractCount` and `productCount` were summed over (#1236). `PERSONAL` when the viewer shares no organization with the subject; `PERSONAL_AND_SHARED_ORGS` when they share at least one.","enum":["PERSONAL","PERSONAL_AND_SHARED_ORGS"],"example":"PERSONAL_AND_SHARED_ORGS"},"countedOrganizations":{"type":"integer","format":"int32","description":"How many organization workspaces were folded into the counts (#1236). Zero when the viewer shares no organization with the subject. Never a list — a count of shared workspaces tells the viewer nothing they could not already enumerate.","example":2}}},"GitHubIdentity":{"type":"object","description":"A linked GitHub identity","properties":{"linked":{"type":"boolean","description":"Whether a GitHub identity is linked","example":true},"login":{"type":"string","description":"The GitHub login","example":"dananewcomer"},"profileUrl":{"type":"string","description":"The GitHub profile URL","example":"https://github.com/dananewcomer"},"profileUrlVerified":{"type":"boolean","description":"Whether the profile's githubUrl came from this link","example":true},"profileUrlConflict":{"type":"boolean","description":"True when a hand-typed profile githubUrl names a different account than the linked one; nothing was overwritten","example":false}}},"LinkedIdentitiesResponse":{"type":"object","description":"Identity providers linked to the calling account (read-only)","properties":{"github":{"$ref":"#/components/schemas/GitHubIdentity","description":"The caller's linked GitHub identity, if any"}}},"PdfSettingsResponse":{"type":"object","description":"The page size and footer a workspace renders its branded PDFs with.","properties":{"size":{"type":"string","description":"Saved page size.","enum":["letter","a4"],"example":"letter"},"footer":{"type":"string","description":"The footer the workspace explicitly set, or null when it has never set one — blank, absent, or still the string the platform shipped. A client should render null as an empty field meaning \"use the automatic workspace copyright\".","example":"Confidential — internal use only"},"effectiveFooter":{"type":"string","description":"The footer actually printed on this workspace's PDFs today. When 'footer' is null this is the automatic copyright built from the workspace owner's name; it is empty when no owner can be identified. Read-only.","example":"Copyright © 2026, Rotten Tometrics, Inc."}}},"PublicOrgResponse":{"type":"object","description":"An organization's public page, as a signed-in Workbench user sees it","properties":{"name":{"type":"string","description":"The organization's name","example":"Actian"},"slug":{"type":"string","description":"The organization's slug","example":"actian"},"logoUrl":{"type":"string","description":"Where to fetch the organization's SVG logo, when it has one. Absent otherwise. The URL is gated exactly like this page — a JWT, and the organization being publicly nameable — so a non-member can render it.","example":"/v4/orgs/actian/public/logo"},"publicMemberCount":{"type":"integer","format":"int64","description":"How many of the organization's members have themselves made their profile public. **Not** the org's headcount: an org of 40 where 3 have opted in reports 3. There is deliberately no way to list who they are.","example":3}}},"MeResponse":{"type":"object","description":"The authenticated user's profile, resolved from the bearer JWT.","properties":{"id":{"type":"integer","format":"int64","description":"Internal numeric user id"},"email":{"type":"string","description":"User email address"},"firstName":{"type":"string","description":"Given name, may be null"},"lastName":{"type":"string","description":"Family name, may be null"},"displayName":{"type":"string","description":"Human-friendly name for the UI greeting — never a UUID"},"isAdmin":{"type":"boolean","description":"Whether the user has platform-admin rights"},"company":{"type":"string","description":"Company name, may be null"},"hasGithubToken":{"type":"boolean","description":"Whether a GitHub token is stored for this user"}}},"ApiKeyResponse":{"type":"object","description":"Response containing the user's API key","properties":{"apiKey":{"type":"string","description":"The user's API key","example":"e7d151da-75e8-40ac-80e8-9e197ed91d61"},"admin":{"type":"boolean","description":"Only present when true. Omitted for non-admin users.","example":true}}},"ActivityLog":{"type":"object","description":"An entry in the activity audit log","properties":{"id":{"type":"integer","format":"int64","example":1042},"userId":{"type":"integer","format":"int64","description":"Associated user ID (null for unauthenticated actions)","example":1},"action":{"type":"string","description":"Human-readable action description (truncated to 254 chars)","example":"User authenticated for ODCS contract upload."},"activityType":{"type":"string","description":"Type of activity recorded in the audit log","enum":["WRONG_RIGHTS","ADMIN_CALL","WRONG_KEY","CREATE_CONTRACT","INFO","ERROR","ERROR_USER","WARNING_SECURITY","CREATE_USER","UPDATE_USER","READ_KEY","INFO_INCOMING_REQUEST","CREATE_PRODUCT","WRONG_PASSWORD","READ_PRODUCT","COMPARE_CONTRACT","DELETE_CONTRACT","DELETE_PRODUCT","SERVER_RESTART","CREDIT_DEDUCT","CREDIT_GRANT","CREDIT_REDEEM","LIST_REFERENCE_TAGS","CREATE_REFERENCE_TAG","UPDATE_REFERENCE_TAG","DELETE_REFERENCE_TAG","V2_REGISTER","V2_VERIFY","V2_LOGIN","V2_REFRESH","V2_ERROR","KEYCLOAK_MIGRATION","CHANGE_PASSWORD","PASSWORD_RESET","ORG_JOIN_REQUEST","ORG_INVITE","ORG_APPROVE","ORG_REJECT","ORG_ACCEPT","ORG_DECLINE","ORG_INVITE_RESEND","ORG_INVITE_REVOKE","ORG_MEMBER_ROLE_CHANGE","ORG_MEMBER_REMOVE","ORG_MEMBER_LEAVE","ORG_TRANSFER_OWNERSHIP","USER_DELETE_BLOCKED_SOLE_OWNER","ORG_CONTRACT_UPLOAD","ORG_PRODUCT_UPLOAD","ORG_ARTIFACT_TRANSFER","OAUTH_REGISTER_SUCCESS","OAUTH_REGISTER_FAILURE","OAUTH_AUTHORIZE_SUCCESS","OAUTH_AUTHORIZE_FAILURE","OAUTH_TOKEN_SUCCESS","OAUTH_TOKEN_FAILURE"],"example":"CREATE_CONTRACT"},"timestamp":{"type":"string","format":"date-time","example":"2026-02-07T10:30:00"},"apiKey":{"type":"string","description":"API key associated with the action","example":"e7d151da-75e8-40ac-80e8-9e197ed91d61"},"apiVersion":{"type":"string","description":"API version used for the call (v1 or v2)","example":"v1"},"activityTypeAsString":{"type":"string"}}},"LeaderboardEntry":{"type":"object","description":"One ranked entry on the leaderboard","properties":{"rank":{"type":"integer","format":"int32","description":"Dense, 1-based rank; users on equal points share a rank","example":1},"userId":{"type":"integer","format":"int64","description":"The ranked user"},"displayName":{"type":"string","description":"Display name — never the full email address. #1228: on a row whose `anonymized` is true this is **already masked**, in the form `J***-G****** P*****`. The real name of a user who has not opted in does not appear in this payload at all.","example":"Priya Raman"},"points":{"type":"integer","format":"int64","description":"Credits earned in the period","example":4820},"self":{"type":"boolean","description":"#1216 — true on the caller's own row, so the UI can label it. At most one row in a response carries it. Identify your own row with this and not by display-name equality: a masked row can never equal your real name, and two masked users can mask to the same string.","example":false},"trueRank":{"type":"integer","format":"int32","description":"#1216 — set only on the caller's own row: their rank among **all** users in scope, before end-to-end test accounts are excluded. Since #1228 stopped hiding users who have not opted in, this is equal to `rank` on almost every board, and differs only when a tester was ranked above the caller.","example":7},"anonymized":{"type":"boolean","description":"#1228 — true when `displayName` on this row has been masked because its owner has not made their profile public. Masking happens on the server, so this flag describes the payload you are holding, not a preference you have to apply: a true value means the name you were sent is already `J***-G****** P*****`. Always false on the caller's own row, which carries their real name whatever their setting.","example":false},"handle":{"type":"string","description":"#1233 — the user's public handle, present **only** when their profile is public. Absent means there is no profile to link to: render the name as plain text. A client cannot accidentally link to a profile that would 404, because it was never given an address. This can never disagree with `anonymized` — both come from the same `UserVisibility.isPublic` decision, so a masked row never carries a handle.","example":"jean-georges.perrin"},"badges":{"type":"array","description":"#1256 — the badges this user has earned, newest first, for the strip under their name. **Capped at 5 per row**: the strip is a summary, not the full award list, and a user with forty badges must not push forty objects into a fifty-row payload. Read the whole list from the user's public profile instead. **Empty on an anonymized row**, always — a badge strip on a masked row would identify the specific person that row belongs to, defeating the masking. Also empty, rather than absent, when a badge lookup fails: a badge problem never turns a leaderboard read into a 500.","items":{"$ref":"#/components/schemas/BadgeAwardResponse"}}}},"Author":{"type":"object","description":"Comment author details","properties":{"userId":{"type":"integer","format":"int64","description":"User ID"},"email":{"type":"string","description":"Email address"},"firstName":{"type":"string","description":"First name"},"lastName":{"type":"string","description":"Last name"},"handle":{"type":"string","description":"#1233 — the author's public handle, present only when their profile is public. Absent means there is no profile to link to: render the name as plain text. A client is never handed an address that would 404.","example":"jean-georges.perrin"}}},"CommentResponse":{"type":"object","description":"Comment or reply returned from the API","properties":{"id":{"type":"string","format":"uuid","description":"Comment UUID"},"orgId":{"type":"string","format":"uuid","description":"Organization UUID"},"artifactKind":{"type":"string","description":"Artifact kind: DataContract or DataProduct"},"artifactId":{"type":"string","description":"Artifact UUID"},"artifactVersion":{"type":"string","description":"Artifact version, or null for all versions"},"orgSlug":{"type":"string","description":"#1497 — the organization's slug, so a client can render or link the org without resolving orgId first. Absent when the organization no longer exists.","example":"acme-analytics"},"artifactName":{"type":"string","description":"#1497 — the artifact's display name. Empty string when there is no artifact to name — a PROFILE comment, or one whose artifact has been deleted. Deliberately \"\" rather than null: the hand-rolled projections have always reported it that way and changing it would be a silent wire change.","example":"Customer 360"},"anchorType":{"type":"string","description":"Anchor granularity: ARTIFACT, SECTION, ELEMENT, or PROFILE (#1217)"},"targetHandle":{"type":"string","description":"#1217 — for a PROFILE comment, the handle of the person whose profile it was left on. Absent on artifact comments.","example":"jean-georges.perrin"},"anchorSection":{"type":"string","description":"YAML section name"},"anchorElementId":{"type":"string","description":"Element id within the section"},"parentId":{"type":"string","format":"uuid","description":"Parent comment UUID for replies; null for top-level"},"author":{"$ref":"#/components/schemas/Author","description":"Comment author"},"body":{"type":"string","description":"Comment body in Markdown"},"resolvedBy":{"type":"integer","format":"int64","description":"User ID who resolved the thread. Kept as a scalar: a client asking \"did I resolve this?\" compares ids, which is a different question from \"who resolved this?\" and deserves a different field. See resolvedByUser (#1486)."},"resolvedByUser":{"$ref":"#/components/schemas/Author","description":"#1486 — who resolved the thread, in the same shape as `author`, so a client can NAME the resolver without a second call. Absent when the thread is unresolved, or when the resolving account no longer exists. `handle` obeys the same public-profile gate as `author`'s (#1233): absent means there is no profile to link to, never that the person has none."},"resolvedAt":{"type":"string","format":"date-time","description":"When the thread was resolved"},"deleted":{"type":"boolean","description":"True only in since-polling responses for soft-deleted comments"},"mentions":{"type":"array","description":"Mentions extracted from the body","items":{"$ref":"#/components/schemas/MentionResponse"}},"reactions":{"type":"object","additionalProperties":{"type":"integer","format":"int64"},"description":"Reaction counts for this comment, keyed by reaction. Reactions with a count of zero are omitted rather than sent as 0, so a client renders what is present instead of filtering. Empty when nobody has reacted (#1448).","example":{"THUMBS_UP":3,"THUMBS_DOWN":1}},"myReaction":{"type":"string","description":"The calling user's own reaction to this comment, or null if they have not reacted. Present so a client can render its button as active without a second call per comment (#1448 AC-4).","example":"THUMBS_UP"},"createdAt":{"type":"string","format":"date-time","description":"When the comment was created"},"updatedAt":{"type":"string","format":"date-time","description":"When the comment was last updated"},"resolved":{"type":"boolean"},"hasBeenEdited":{"type":"boolean","description":"Whether the body was edited after creation"},"isResolved":{"type":"boolean","description":"Whether this thread is resolved"}}},"MentionResponse":{"type":"object","description":"An @mention from the comment body","properties":{"id":{"type":"string","format":"uuid","description":"Mention UUID"},"email":{"type":"string","description":"Mentioned email"},"userId":{"type":"integer","format":"int64","description":"Mentioned user ID (null if user does not exist)"},"taskCompletedAt":{"type":"string","format":"date-time","description":"When the task was completed"},"task":{"type":"boolean"},"isTask":{"type":"boolean","description":"Whether this is a task assignment"},"taskCompleted":{"type":"boolean","description":"Whether the task was completed"}}},"BadgeCatalogEntry":{"type":"object","description":"One badge in the public catalog","properties":{"id":{"type":"string","description":"Stable badge id","example":"podemaster_bronze"},"name":{"type":"string","description":"Display name","example":"Podemaster"},"tier":{"type":"string","description":"Tier within the family; null for untiered badges","example":"Bronze"},"description":{"type":"string","description":"Short description","example":"Created 5 artifacts"},"imageUrl":{"type":"string","description":"Where the badge art is served from","example":"/v4/badges/podemaster_bronze/image"}}},"UnseenBadgeAward":{"type":"object","description":"An award the caller has not yet acknowledged","properties":{"id":{"type":"string","description":"Award id — pass this to PUT /v4/badges/{awardId}/seen"},"badgeId":{"type":"string","description":"Catalog badge id","example":"podemaster_bronze"},"name":{"type":"string","description":"Display name, from the template","example":"Podemaster"},"tier":{"type":"string","description":"Tier, from the template; null for untiered badges","example":"Bronze"},"imageUrl":{"type":"string","description":"Badge art","example":"/v4/badges/podemaster_bronze/image"},"awardedAt":{"type":"string","format":"date-time","description":"When it was earned"}}},"BadgeTemplate":{"type":"object","description":"A design-time badge class — what can be earned","properties":{"id":{"type":"string","description":"Stable badge id","example":"podemaster_bronze"},"name":{"type":"string","description":"Display name, shared across a tiered family","example":"Podemaster"},"tier":{"type":"string","description":"Tier within a family; null for untiered badges","example":"Bronze"},"description":{"type":"string","description":"Short catalog description","example":"Created 5 artifacts"},"criteriaNarrative":{"type":"string","description":"Plain-language statement of what earns this, baked into the Open Badges credential (WB3 #1246)"},"criteriaType":{"type":"string","description":"count | multi | days_since_joined | leaderboard_rank","example":"count"},"criteriaValue":{"type":"string","description":"JSON: a threshold integer, or a multi-criteria object","example":{"threshold":5}},"criteriaSource":{"type":"string","description":"Names the counting strategy — the attribution rule, as configuration","example":"activity_log:CREATE_CONTRACT,CREATE_PRODUCT"},"imagePath":{"type":"string","description":"Classpath-relative source art, the input to credential baking","example":"badges/podemaster_bronze.png"},"enabled":{"type":"boolean","description":"Switch a badge out of the catalog without a deploy"},"sortOrder":{"type":"integer","format":"int32","description":"Catalog render order — deliberate, not primary-key order"}}},"ArtifactHeader":{"type":"object","description":"Unified artifact header (contract or product)","properties":{"id":{"type":"string","description":"Artifact ID (UUID for products, slug/UUID for contracts)"},"kind":{"type":"string","description":"Artifact kind. Both vocabularies are accepted on input, permanently. Emitted as 'DataContract'/'DataProduct' — the spelling the ODCS and ODPS standards use. v1 and v2 responses keep the legacy 'contract'/'product' spelling permanently.","enum":["contract","product","DataContract","DataProduct"],"example":"DataContract"},"name":{"type":"string","description":"Display name"},"version":{"type":"string","description":"Semantic version (e.g., 1.0.0)"},"status":{"type":"string","description":"Lifecycle status (e.g., draft, active, deprecated)"},"domain":{"type":"string","description":"Domain the artifact belongs to (free-form)"},"owner":{"type":"string","description":"Owner / tenant identifier"},"updated":{"type":"string","description":"ISO-8601 last-updated timestamp, when available"},"tags":{"type":"array","description":"Free-form tags from the artifact YAML","items":{"type":"string"}},"maturityLevel":{"type":"integer","format":"int32","description":"Maturity level (null when no assessment is available)"},"maturityLevelLabel":{"type":"string","description":"Maturity level label (null when no assessment is available)"},"org":{"type":"string","description":"Org slug the artifact lives in (null = personal storage)"},"commentCount":{"type":"integer","format":"int32","description":"Number of unresolved top-level comment threads. Always 0 for personal artifacts, since comments are an org-scoped feature."},"signed":{"type":"boolean","description":"True when the artifact carries a signature block"},"signedAt":{"type":"string","description":"ISO-8601 signing timestamp (null when unsigned)"},"signerName":{"type":"string","description":"Signer display name (null when unsigned or not recorded)"},"autosign":{"type":"boolean","description":"Per-artifact auto-sign opt-out (#855/#864): false when the document carries customProperties autosign=false (stamped by an unsign; cleared by a manual sign). Null when the artifact never opted out."},"certificateFingerprint":{"type":"string","description":"Leaf-certificate SHA-256 fingerprint of the signature (null when unsigned or the signature could not be read)"},"signatureValid":{"type":"boolean","description":"Signature validity: true = verified, false = invalid/tampered, null = unsigned (no crypto run)"},"syncStatus":{"type":"string","description":"Latest Zeenea sync status for this version: success | failed (null when never synced) (#758)"},"syncedAt":{"type":"string","description":"ISO-8601 timestamp of the latest Zeenea sync (null when never synced)"},"syncUploadId":{"type":"string","description":"Dispatcher upload id of the latest sync (null when absent)"},"syncError":{"type":"string","description":"Failure message from the latest Zeenea sync (null unless it failed)"},"deprecated":{"type":"boolean","description":"RFC-0051 artifact-level deprecation marker, read verbatim from the stored document's root `deprecated`. **Products only**: ODPS v1.1.0 defines `deprecated` at the product root, while ODCS has no contract-root equivalent (it places `deprecated` on schema objects and properties), so a contract row is always null. Independent of `status`, which is the lifecycle state and may read \"deprecated\" without this flag being set, or vice versa."},"apiVersion":{"type":"string","description":"The standard edition the document itself declares (`apiVersion`), verbatim and never defaulted, coerced or normalized: a document declaring `v3.0.2` reports `v3.0.2`, and one declaring nothing reports null. Distinct from `version`, which is the artifact's own semantic version.","example":"v3.2.0"}}},"ArtifactListResponse":{"type":"object","description":"Unified artifact listing: header rows plus a total count","properties":{"items":{"type":"array","description":"The caller's artifact headers across personal + every org they belong to","items":{"$ref":"#/components/schemas/ArtifactHeader"}},"total":{"type":"integer","format":"int32","description":"Number of headers in items (== items.length)"}}},"TestRunSuiteHealth":{"type":"object","description":"One test suite as the alert job sees it: its streak, cadence and silence","properties":{"suite":{"type":"string","description":"The suite, as `app / process [provenance]`","example":"wb2 / e2e [admin-invitations]"},"app":{"type":"string","description":"The diagnostics `app` of its runs","example":"wb2"},"process":{"type":"string","description":"The suite's `source.process`","example":"e2e"},"provenance":{"type":"string","description":"The runs' provenance","example":"admin-invitations"},"runs":{"type":"integer","format":"int32","description":"Runs inside the lookback window"},"lastRunAt":{"type":"string","format":"date-time","description":"When the latest run reported"},"lastSummary":{"type":"string","description":"The latest run's summary line"},"redStreak":{"type":"integer","format":"int32","description":"Consecutive red finished runs, newest backwards; a zero-test run is red"},"zeroTestRunsInStreak":{"type":"integer","format":"int32","description":"How many runs in that streak executed zero tests"},"medianIntervalMinutes":{"type":"integer","format":"int64","description":"Median minutes between recent runs; null while no cadence is established"},"minutesSinceLastRun":{"type":"integer","format":"int64","description":"Minutes since the latest run reported"},"redStreakAlert":{"type":"boolean","description":"True when the red streak has reached the alert threshold"},"silent":{"type":"boolean","description":"True when reports stopped arriving within the suite's own cadence"},"muted":{"type":"boolean","description":"True when alerts on this suite are muted"}}},"InteractionExportPage":{"type":"object","description":"One page of exported Governance Coach interactions","properties":{"items":{"type":"array","description":"Interactions in this page — coach and A2A agent, merged and ordered by (day, id) ascending. Each row's `source` says which produced it.","items":{"$ref":"#/components/schemas/InteractionRecordDto"}},"nextCursor":{"type":"string","description":"Opaque cursor for the next page; null when the range is exhausted"},"count":{"type":"integer","format":"int32","description":"Number of items in this page"},"from":{"type":"string","format":"date","description":"Inclusive start of the range actually applied"},"to":{"type":"string","format":"date","description":"Inclusive end of the range actually applied"},"limit":{"type":"integer","format":"int32","description":"Page size actually applied, after clamping"}}},"InteractionRecordDto":{"type":"object","description":"#1484 — one interaction, from the coach or from an A2A agent","properties":{"source":{"type":"string","description":"Which source produced this row","enum":["coach","agent"],"example":"coach"},"id":{"type":"string","format":"uuid"},"day":{"type":"string","format":"date","description":"Date precision, UTC — the keyset's first component"},"orgHash":{"type":"string","description":"#1483 — the peppered organization hash, or null"},"pseudonymId":{"type":"string","format":"uuid","description":"Coach only. Null on an agent row."},"questionText":{"type":"string","description":"Coach only — the user's question. Null on an agent row, and never populated for one: an A2A payload has already left the platform."},"answerText":{"type":"string","description":"Coach only — the answer. Null on an agent row."},"artifactKind":{"type":"string","description":"Coach only"},"maturityGaps":{"type":"array","description":"Coach only","items":{"type":"string"}},"retrievedPaths":{"type":"array","description":"Coach only","items":{"type":"string"}},"section":{"type":"string","description":"Coach only"},"source2":{"type":"string","description":"Coach only — where the interaction came from"},"artifactHash":{"type":"string","description":"Coach only — the per-user artifact hash (#1198), never an artifact id"},"sessionId":{"type":"string","description":"Coach only — the client's opaque session id"},"agentCardUrl":{"type":"string","description":"Agent only — which agent was called"},"outcome":{"type":"string","description":"Agent only — ok, error or refused"},"durationMs":{"type":"integer","format":"int64","description":"Agent only — wall-clock duration"},"responseChars":{"type":"integer","format":"int32","description":"Agent only — the SIZE of the reply, never its content"},"appVersion":{"type":"string","description":"Client app version, when the source records one"}}},"CoachInteractionRollupPage":{"type":"object","description":"The weekly Governance Coach rollup for a date range","properties":{"items":{"type":"array","description":"Weekly counters, ordered by isoWeek, then retrievedPath, maturityGap and section","items":{"$ref":"#/components/schemas/CoachInteractionRollupRow"}},"count":{"type":"integer","format":"int32","description":"Number of counters returned"},"from":{"type":"string","format":"date","description":"Inclusive start of the range actually applied"},"to":{"type":"string","format":"date","description":"Inclusive end of the range actually applied"},"fromWeek":{"type":"string","description":"ISO week containing `from`: the first week the range covers","example":"2026-W14"},"toWeek":{"type":"string","description":"ISO week containing `to`: the last week the range covers","example":"2026-W27"}}},"CoachInteractionRollupRow":{"type":"object","description":"One weekly Governance Coach counter that survives retention: how much, of what kind, in which week. It carries no pseudonym, session or organization, because the rollup stores none.","properties":{"retrievedPath":{"type":"string","description":"One retrieved path, or `(none)`","example":"schema.properties.quality"},"maturityGap":{"type":"string","description":"One failing maturity criterion id, or `(none)`","example":"fundamentals.owner"},"section":{"type":"string","description":"Editor section at ask-time, or `(none)`","example":"fundamentals"},"isoWeek":{"type":"string","description":"ISO week the rolled-up interactions fell in","example":"2026-W29"},"count":{"type":"integer","format":"int64","description":"Number of interactions rolled into this bucket","example":12}}},"ContractForceDeleteResponse":{"type":"object","description":"Result of a force delete: the deleted contract and the products it was detached from (#1397).","properties":{"deleted":{"$ref":"#/components/schemas/Deleted","description":"The contract version that was deleted"},"detached":{"type":"array","description":"One entry per data product modified in place, empty when none referenced the contract","items":{"$ref":"#/components/schemas/DetachedProduct"}}}},"Deleted":{"type":"object","description":"The deleted contract","properties":{"contractId":{"type":"string","description":"Contract identifier","example":"34cae6d7-7648-38b2-8f66-8db79e1e2ce4"},"version":{"type":"string","description":"Semantic version, no v prefix","example":"1.0.0"}}},"DetachedProduct":{"type":"object","description":"A data product the contract was detached from, in place, at its current version","properties":{"productId":{"type":"string","description":"Product identifier","example":"0d9b3c1e-3f36-4a49-9a83-2d0e6b6f0c2a"},"productVersion":{"type":"string","description":"Product version, unchanged by the detach","example":"2.1.0"},"name":{"type":"string","description":"Product name","example":"Customer 360"},"portsRemoved":{"type":"integer","format":"int32","description":"Number of references removed across inputPorts, outputPorts and outputPorts[].inputContracts","example":3}}}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","description":"UUID API key obtained during registration","name":"X-API-KEY","in":"header"},"PasswordAuth":{"type":"apiKey","description":"User's plaintext password","name":"X-USER-PASSWORD","in":"header"},"BearerAuth":{"type":"http","description":"Bearer JWT token from Keycloak. Used by v2 endpoints.","scheme":"bearer","bearerFormat":"JWT"}}}}