diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0341f7d..7f66deb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,4 +15,5 @@ jobs: steps: - uses: actions/checkout@v7 - uses: jdx/mise-action@v2 - - run: task check + - run: bun install --frozen-lockfile + - run: mise run check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f54089f..bbca2b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,13 +11,16 @@ permissions: jobs: release: runs-on: ubuntu-latest + strategy: + matrix: + target: + - linux-x64 steps: - uses: actions/checkout@v7 - with: - fetch-depth: 0 - uses: jdx/mise-action@v2 - - run: task check - - run: goreleaser release --clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + - run: bun install --frozen-lockfile + - run: mise run check + - run: bun build src/bin/akua.ts --compile --target=bun-${{ matrix.target }} --outfile dist/akua-${{ matrix.target }} + - uses: softprops/action-gh-release@v2 + with: + files: dist/akua-${{ matrix.target }} diff --git a/.github/workflows/update-api-client.yml b/.github/workflows/update-api-client.yml deleted file mode 100644 index 5157d53..0000000 --- a/.github/workflows/update-api-client.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Update API Client - -on: - schedule: - - cron: "0 9 * * 1" # Monday 9am UTC - workflow_dispatch: - inputs: - api_url: - description: "API base URL to fetch OpenAPI spec from" - default: "https://api.cnap.tech" - -permissions: - contents: write - pull-requests: write - -jobs: - update: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: jdx/mise-action@v2 - - - name: Fetch OpenAPI spec - run: | - API_URL="${{ inputs.api_url || 'https://api.cnap.tech' }}" - curl -fsSL "${API_URL}/v1/openapi.json" -o internal/api/openapi.json - echo "Fetched spec from ${API_URL}/v1/openapi.json" - - - name: Regenerate client - run: task generate - - - name: Verify build - run: task check - - - uses: peter-evans/create-pull-request@v8 - with: - branch: chore/update-api-client - commit-message: "chore: update OpenAPI spec and regenerate client" - title: "chore: update OpenAPI spec and regenerate client" - body: | - Automated weekly update of the OpenAPI spec from the public API. - - - Fetched `/v1/openapi.json` - - Regenerated `client.gen.go` via `oapi-codegen` - - Verified `task check` passes - delete-branch: true diff --git a/.github/workflows/update-openapi.yml b/.github/workflows/update-openapi.yml new file mode 100644 index 0000000..937ae09 --- /dev/null +++ b/.github/workflows/update-openapi.yml @@ -0,0 +1,33 @@ +name: Update OpenAPI + +on: + schedule: + - cron: "0 9 * * 1" + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: jdx/mise-action@v2 + - run: bun install --frozen-lockfile + - run: mise run spec:fetch + - run: mise run generate + - run: mise run check + - uses: peter-evans/create-pull-request@v8 + with: + branch: chore/update-openapi + commit-message: "chore: update OpenAPI spec and command registry" + title: "chore: update OpenAPI spec and command registry" + body: | + Automated weekly update of the public Akua OpenAPI snapshot. + + - Fetched `https://api.akua.dev/v1/openapi.json` + - Regenerated the public operation command registry + - Verified `mise run check` + delete-branch: true diff --git a/.gitignore b/.gitignore index 5b98636..3320357 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ -# Binary -/cnap dist/ +node_modules/ # OS .DS_Store diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 310fefb..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: "2" -linters: - enable: - - errcheck - - govet - - ineffassign - - staticcheck - - unused - - gocritic - - misspell - - nilerr - - errorlint -formatters: - enable: - - gofmt - - goimports -issues: - exclude-generated-files: true diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index 5482690..0000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,69 +0,0 @@ -version: 2 -project_name: cnap - -before: - hooks: - - go mod tidy - - mkdir -p completions - - sh -c "go run ./cmd/cnap completion bash > completions/cnap.bash" - - sh -c "go run ./cmd/cnap completion zsh > completions/cnap.zsh" - - sh -c "go run ./cmd/cnap completion fish > completions/cnap.fish" - -builds: - - main: ./cmd/cnap/ - binary: cnap - env: - - CGO_ENABLED=0 - ldflags: - - -s -w - - -X github.com/cnap-tech/cli/internal/cmd.version={{.Version}} - - -X github.com/cnap-tech/cli/internal/cmd.commit={{.ShortCommit}} - goos: - - linux - - darwin - - windows - goarch: - - amd64 - - arm64 - -archives: - - formats: [tar.gz] - format_overrides: - - goos: windows - formats: [zip] - name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - files: - - completions/* - -brews: - - skip_upload: "{{ if .Env.HOMEBREW_TAP_TOKEN }}false{{ else }}true{{ end }}" - repository: - owner: cnap-tech - name: homebrew-tap - token: "{{ .Env.HOMEBREW_TAP_TOKEN }}" - directory: Formula - homepage: https://docs.cnap.tech/cli - description: CLI for managing CNAP workspaces, clusters, and deployments - install: | - bin.install "cnap" - bash_completion.install "completions/cnap.bash" => "cnap" - zsh_completion.install "completions/cnap.zsh" => "_cnap" - fish_completion.install "completions/cnap.fish" - test: | - assert_match version.to_s, shell_output("#{bin}/cnap --version") - -checksum: - name_template: checksums.txt - -changelog: - sort: asc - filters: - exclude: - - "^docs:" - - "^ci:" - - "^chore:" - -release: - github: - owner: cnap-tech - name: cli diff --git a/README.md b/README.md index 6540125..6124375 100644 --- a/README.md +++ b/README.md @@ -1,187 +1,81 @@ -# CNAP CLI +# Akua CLI -Command-line interface for managing CNAP workspaces, clusters, and deployments. +Greenfield Akua Cloud CLI prototype. -## Install +The canonical binary is `akua`. This repository is intentionally moving away +from the old CNAP-era Go CLI; no `cnap` binary or +`github.com/cnap-tech/cli` compatibility is required for the first Akua +release. -```bash -# Homebrew (macOS / Linux) — includes shell completions -brew install cnap-tech/tap/cnap +## Current Status -# Go -go install github.com/cnap-tech/cli/cmd/cnap@latest +This scaffold establishes the architecture, packaging path, OpenAPI fetch task, +public operation registry generation, and output/error runtime contract. It does +not yet implement full API command execution. -# GitHub Releases — download binary for your platform -# https://github.com/cnap-tech/cli/releases -``` - -## Quick Start - -```bash -# Authenticate via browser (stores session token) -cnap auth login - -# Or authenticate with a Personal Access Token (for CI/CD) -cnap auth login --token cnap_pat_... - -# List and select a workspace -cnap workspaces list -cnap workspaces switch - -# Manage clusters -cnap clusters list -cnap clusters get - -# Deploy a product -cnap installs create --product --region - -# Stream logs -cnap installs logs --follow -``` - -## Shell Completions - -Homebrew installs completions automatically. For manual installs: - -### Zsh +## Development -```bash -# Current session -source <(cnap completion zsh) +Prerequisites: -# Permanent (macOS with Homebrew) -cnap completion zsh > $(brew --prefix)/share/zsh/site-functions/_cnap +- [mise](https://mise.jdx.dev/) +- Bun, installed by `mise install` -# Permanent (Linux) -cnap completion zsh > "${fpath[1]}/_cnap" +```sh +mise install +bun install +mise run spec:fetch +mise run generate +mise run check ``` -If completions don't work, ensure `compinit` is loaded in your `~/.zshrc`: +Useful tasks: -```bash -autoload -U compinit; compinit +```sh +mise run dev -- --help # run the TypeScript entrypoint +mise run build # typecheck and build JS into dist/js/ +mise run build:binary # compile self-contained dist/akua +mise run test # run Bun tests +mise run spec:fetch # fetch https://api.akua.dev/v1/openapi.json +mise run generate # regenerate public command registry +mise run generate:check # verify generated registry is current ``` -### Bash - -Requires the `bash-completion` package (`brew install bash-completion@2` on macOS). - -```bash -# Current session -source <(cnap completion bash) - -# Permanent (macOS with Homebrew) -cnap completion bash > $(brew --prefix)/etc/bash_completion.d/cnap +Implemented scaffold commands: -# Permanent (Linux) -cnap completion bash > /etc/bash_completion.d/cnap +```sh +akua # show compact registry status +akua commands # list first 20 generated public commands +akua commands --resource workspaces # filter by generated resource +akua commands --operation-id workspaces.list +akua commands --limit 5 +akua --help # also -h +akua --version # also -v or -V ``` -### Fish +## OpenAPI Source -```bash -# Current session -cnap completion fish | source +The live production source of truth is: -# Permanent -cnap completion fish > ~/.config/fish/completions/cnap.fish +```text +https://api.akua.dev/v1/openapi.json ``` -## Configuration - -Config is stored at `~/.cnap/config.yaml`. Environment variables take priority: - -| Env Var | Description | -|---------|-------------| -| `CNAP_API_TOKEN` | API token — PAT or session token (overrides config) | -| `CNAP_API_URL` | API base URL (overrides config) | -| `CNAP_AUTH_URL` | Auth base URL (overrides config) | -| `CNAP_DEBUG` | Enable debug logging (set to any value) | -| `CNAP_NO_UPDATE_NOTIFIER` | Disable update notifications (set to any value) | - -## Global Flags - -| Flag | Description | -|------|-------------| -| `-o, --output` | Output format: `table`, `json`, `quiet` | -| `--api-url` | API base URL override | -| `--debug` | Enable debug logging (HTTP traces to stderr) | - -## Commands - -All resource commands support singular and plural forms (e.g. `cnap cluster` or `cnap clusters`), -short aliases (e.g. `cl`, `inst`, `tpl`), and `ls` as an alias for `list`. - -When run interactively without an ID argument, commands show a picker to select a resource. -Delete commands prompt for confirmation unless `--yes`/`-y` is passed. - -| Command | Description | -|---------|-------------| -| **Auth** | | -| `cnap auth login` | Authenticate via browser (stores session token) | -| `cnap auth login --token ` | Authenticate with a PAT | -| `cnap auth logout` | Remove credentials (revokes session) | -| `cnap auth status` | Show auth status and token type | -| **Workspaces** | | -| `cnap workspaces list` | List workspaces | -| `cnap workspaces switch [id]` | Set active workspace | -| **Clusters** | | -| `cnap clusters list` | List clusters | -| `cnap clusters get [id]` | Get cluster details | -| `cnap clusters update [id]` | Update cluster | -| `cnap clusters delete [id]` | Delete cluster (confirms interactively) | -| `cnap clusters kubeconfig [id]` | Download admin kubeconfig | -| **Templates** | | -| `cnap templates list` | List templates | -| `cnap templates get [id]` | Get template with helm sources | -| `cnap templates delete [id]` | Delete template (confirms interactively) | -| **Products** | | -| `cnap products list` | List products | -| `cnap products get [id]` | Get product details | -| `cnap products delete [id]` | Delete product (confirms interactively) | -| **Installs** | | -| `cnap installs list` | List installs | -| `cnap installs get [id]` | Get install details | -| `cnap installs create --product --region ` | Create product install | -| `cnap installs update-values [id] --source -f values.yaml` | Update template values | -| `cnap installs update-overrides [id] --source -f values.yaml` | Update install overrides | -| `cnap installs delete [id]` | Delete install (confirms interactively) | -| `cnap installs pods [id]` | List pods | -| `cnap installs logs [id] [--pod X] [--follow] [--tail N]` | Stream logs | -| `cnap installs exec [id] [--pod X] [--container X]` | Open interactive shell in pod | -| **Regions** | | -| `cnap regions list` | List regions | -| `cnap regions create --name ` | Create region | -| **Registry** | | -| `cnap registry list` | List registry credentials | -| `cnap registry delete [id]` | Delete registry credential (confirms interactively) | -| **Shell Completions** | | -| `cnap completion bash` | Generate bash completions | -| `cnap completion zsh` | Generate zsh completions | -| `cnap completion fish` | Generate fish completions | +`mise run spec:fetch` writes the fetched snapshot to `openapi/public.json`. +`mise run generate` reads that snapshot and writes +`src/generated/commands.gen.ts`. +The fetcher defaults to `AKUA_OPENAPI_URL` when set and rejects non-HTTPS +override URLs. -## Development - -Prerequisites: [mise](https://mise.jdx.dev) for tool management. +## Runtime Contract -```bash -# Install tools (Go, golangci-lint, goreleaser, task) -mise install +Default output is adaptive: -# Regenerate API client from OpenAPI spec -task generate +- coding-agent, CI, non-TTY, and automation signals use compact structured + agent output; +- interactive TTY sessions use human output; +- `--json`, `--quiet`, `-q`, `--output `, `-o `, and `AKUA_OUTPUT` + override detection. -# Run all checks (vet + lint + test) -task check - -# Individual commands -task build # Build binary -task lint # Run golangci-lint -task vet # Run go vet -task fmt # Format code -task test # Run tests -task release:snapshot # Build snapshot release locally -task clean # Remove build artifacts -``` +Supported output modes are `human`, `agent`, `json`, and `quiet`. -The API client is auto-generated from the OpenAPI spec at `internal/api/openapi.json` using [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen). +See [docs/architecture.md](docs/architecture.md) for the full CLI spec. diff --git a/Taskfile.yml b/Taskfile.yml deleted file mode 100644 index c9574ec..0000000 --- a/Taskfile.yml +++ /dev/null @@ -1,52 +0,0 @@ -version: "3" - -set: [errexit, pipefail] - -tasks: - build: - desc: Build the CLI binary - cmds: - - go build -o cnap ./cmd/cnap/ - - generate: - desc: Regenerate API client from OpenAPI spec - cmds: - - go tool oapi-codegen -config internal/api/oapi-codegen.yaml internal/api/openapi.json - - lint: - desc: Run golangci-lint - cmds: - - golangci-lint run - - vet: - desc: Run go vet - cmds: - - go vet ./... - - fmt: - desc: Format code - cmds: - - golangci-lint fmt - - test: - desc: Run tests - cmds: - - go test ./... - - check: - desc: Run all checks (vet + lint + test) - cmds: - - task: vet - - task: lint - - task: test - - release:snapshot: - desc: Build a snapshot release locally (no publish) - cmds: - - goreleaser release --snapshot --clean - - clean: - desc: Remove build artifacts - cmds: - - rm -f cnap - - rm -rf dist/ diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..ffe2adf --- /dev/null +++ b/bun.lock @@ -0,0 +1,24 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "@akua-dev/cli", + "devDependencies": { + "@types/bun": "^1.3.0", + "typescript": "^5.9.0", + }, + }, + }, + "packages": { + "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + + "@types/node": ["@types/node@26.1.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], + + "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], + } +} diff --git a/cmd/cnap/main.go b/cmd/cnap/main.go deleted file mode 100644 index 5598011..0000000 --- a/cmd/cnap/main.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - - "github.com/cnap-tech/cli/internal/cmd" -) - -func main() { - os.Exit(run()) -} - -func run() int { - ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) - defer stop() - - if err := cmd.Execute(ctx); err != nil { - fmt.Fprintf(os.Stderr, "Error: %s\n", err) - return 1 - } - return 0 -} diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..2a6ef32 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,262 @@ +# Akua Cloud CLI Architecture + +Status: initial greenfield spec and scaffold. + +## Decisions And Non-Goals + +- Binary: `akua`. +- Runtime: Bun and TypeScript. +- Repository: standalone open-source `akua-dev/cli`. +- Packaging: Bun self-contained executable via `bun build --compile`. +- API source of truth: `https://api.akua.dev/v1/openapi.json`. +- First release: public API commands only. +- Compatibility: no `cnap` binary, Go module, config path, env var, or command + compatibility unless a later captain decision changes this. +- No live infrastructure mutation is required for development or tests. The + spec fetch task performs only a read-only OpenAPI GET and rejects non-HTTPS + source URLs. + +## Current Repo Boundary + +The old Go/CNAP implementation is removed from the active build surface. The +new repository shape is: + +```text +openapi/public.json fetched public OpenAPI snapshot +scripts/fetch-openapi.ts guarded production spec fetcher +scripts/generate-commands.ts operationId-driven command registry generator +src/bin/akua.ts executable entrypoint +src/runtime/ output, errors, exit codes, command contracts +src/generated/commands.gen.ts generated public command registry +docs/architecture.md this spec +test/ Bun tests for scaffold contracts +``` + +## OpenAPI And Command Generation + +The CLI is operationId-driven. Public OpenAPI operations become generated command +definitions when all of these are true: + +- `x-platform-visibility` is `PUBLIC`; +- `operationId` is present; +- HTTP method and path are present; +- tags, summary, operation-level auth requirement, and parameters are copied + into the command model when present. + +The initial command derivation is mechanical: + +```text +operationId: workspaces.list +command: akua workspaces list + +operationId: customDomains.delete +command: akua custom-domains delete + +operationId: health +command: akua health get +``` + +An operationId segment before the first dot becomes the resource, the next +segment becomes the action, and single-segment operationIds fall back to the +HTTP method as the action. The generator assumes OpenAPI operationIds are +unique; it does not currently enforce uniqueness itself. + +The generator deliberately produces a registry, not hand-written API coverage. +Execution is stubbed until the API client and request/body binding layer lands. +The next implementation step should add a small CLI overlay file for exceptions +that cannot be inferred safely from OpenAPI alone, such as preferred aliases, +default list fields, destructive-command confirmation labels, and resource- +specific next steps. + +Generation tasks: + +```sh +mise run spec:fetch # writes openapi/public.json +mise run generate # writes src/generated/commands.gen.ts +mise run generate:check # fails on drift +``` + +`mise run spec:fetch` defaults to `AKUA_OPENAPI_URL`, which is set to the +production source in `mise.toml`, and `scripts/fetch-openapi.ts` also accepts an +explicit URL argument. The scheduled `Update OpenAPI` workflow runs weekly and +opens a pull request after fetching the snapshot, regenerating the registry, and +running `mise run check`. + +## API, Auth, And Config Model + +Default API base URL: + +```text +https://api.akua.dev/v1 +``` + +Authentication: + +- bearer tokens use `Authorization: Bearer sk_akua_...`; +- `AKUA_API_TOKEN` is the primary noninteractive credential env var; +- broad tokens select workspace/scope with the `Akua-Context` header; +- workspace-owned tokens may imply workspace context. + +Configuration should live under the Akua namespace: + +```text +~/.config/akua/config.json +``` + +Recommended config precedence: + +1. command flags such as `--api-url`, `--workspace`, and `--profile`; +2. environment variables; +3. profile config; +4. built-in production defaults. + +The first release should implement `akua auth login --token `, `akua auth +status`, and `akua auth logout` before browser/device login. Tokens must be +stored with user-only file permissions. + +## Output And UX Modes + +The default output mode is adaptive: + +- `human`: interactive TTY without automation or coding-agent signals; +- `agent`: known coding-agent env vars, CI env vars, or non-TTY stdout; +- `json`: explicit `--json`, `--output json`, `-o json`, or + `AKUA_OUTPUT=json`; +- `quiet`: explicit `--quiet`, `-q`, `--output quiet`, `-o quiet`, or + `AKUA_OUTPUT=quiet`. + +`--output`/`-o` and `AKUA_OUTPUT` accept only `human`, `agent`, `json`, and +`quiet`. `--json` and `--quiet` take precedence over other output mode signals. + +Agent mode follows AXI patterns studied from `https://axi.md/` and the public +`gh-axi` example: + +- compact structured output, currently TOON-like text; +- small list schemas by default; +- explicit empty states; +- contextual `next_steps`; +- stdout for success data and structured errors; +- stderr for progress, debug logs, and warnings; +- no spinners or prompts in agent, JSON, quiet, CI, or non-TTY modes; +- unknown routed commands and flags must fail loudly. + +Human mode can use tables and prose, but should stay content-first. A no-args +`akua` invocation should show live state once API execution exists; the scaffold +currently shows registry state and next-step commands. + +The implemented scaffold command surface is intentionally small: + +```sh +akua # registry status home view +akua commands # first 20 generated public commands +akua commands --resource workspaces # resource filter +akua commands --operation-id workspaces.list +akua commands --limit 5 # positive integer limit +akua --help # also -h +akua --version # also -v or -V +``` + +## Structured Errors + +Errors preserve API envelope details instead of collapsing them into strings: + +```json +{ + "error": { + "type": "validation_error", + "code": "INVALID_ARGUMENT", + "status": 400, + "message": "workspace_id is required", + "path": ["body", "workspace_id"], + "request_id": "req_123", + "next_steps": [ + {"command": "akua workspaces list --fields id,name"} + ] + } +} +``` + +The same payload shape is used in JSON and agent modes. Human mode can render a +readable summary, but should include request IDs and next steps. + +## Exit Codes + +Initial contract: + +- `0`: success, including idempotent no-op success; +- `1`: runtime or API error; +- `2`: local usage error, unknown command, unknown flag, invalid local args; +- `3`: authentication/session required; +- `4`: confirmation required or unsafe noninteractive mutation refused; +- `5`: conflict/precondition failure, including `If-Match` mismatch; +- `6`: retryable upstream failure or rate limit. + +This can be simplified later, but it must remain deterministic and tested. + +## Public-Only First Release + +The first release command surface is generated only from public operations. +Internal, admin, preview, trusted-partner, and private operations must be absent +from generated commands and docs unless a separate build target is deliberately +added later. + +Recommended MVP order: + +1. `auth` and config/profile commands; +2. workspace/context commands; +3. read-only `list` and `get` commands for public resources; +4. operations status/watch commands; +5. selected mutations with idempotency and confirmation safety. + +## Mutations And Safety + +For create/update/delete commands: + +- destructive actions require explicit resource IDs; +- noninteractive destructive actions require `--yes` or `--force`; +- `Idempotency-Key` is required when the API supports it, generated if omitted, + and included in structured output; +- `If-Match` must be supported for resources with `etag`; +- `--dry-run`, `--wait`, `--watch`, and structured streaming should be added only + where the API contract supports them; +- prompts are forbidden in automation modes. + +## Packaging + +The packaging path is: + +```sh +bun build src/bin/akua.ts --compile --target=bun-linux-x64 --outfile dist/akua-linux-x64 +``` + +The local task `mise run build:binary` compiles a host binary at `dist/akua`. +The initial release workflow builds a Linux x64 artifact; macOS and Windows +matrix targets should be added once the scaffold is validated on CI. + +## Testing Strategy + +Current tests cover: + +- CLI routing and usage validation for the scaffold commands; +- output mode detection; +- agent and JSON rendering; +- structured error payloads; +- OpenAPI fetch guard and document shape validation; +- public-only operation collection. + +Current validation also runs `mise run generate:check` to catch generated +registry drift. + +Next tests should add: + +- golden command output by mode; +- mocked API calls for auth, workspace, list/get, and operation flows; +- destructive command refusal tests in CI/non-TTY/agent modes; +- packaging smoke test for `dist/akua --help`. + +## Migration Boundary + +This is not a compatibility migration. The old `cnap` CLI can remain available +through historical releases until product documentation points users at the new +`akua` binary. New code should not import or preserve old CNAP module paths, +config paths, env vars, token prefixes, release metadata, or Homebrew formulas. diff --git a/go.mod b/go.mod deleted file mode 100644 index 20a4ac0..0000000 --- a/go.mod +++ /dev/null @@ -1,74 +0,0 @@ -module github.com/cnap-tech/cli - -go 1.26.0 - -require ( - github.com/charmbracelet/huh v0.8.0 - github.com/charmbracelet/lipgloss v1.1.0 - github.com/coder/websocket v1.8.14 - github.com/oapi-codegen/runtime v1.1.2 - github.com/spf13/cobra v1.10.2 - golang.org/x/term v0.40.0 - gopkg.in/yaml.v3 v3.0.1 -) - -require ( - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/atotto/clipboard v0.1.4 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/catppuccin/go v0.3.0 // indirect - github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect - github.com/charmbracelet/bubbletea v1.3.6 // indirect - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect - github.com/charmbracelet/x/ansi v0.9.3 // indirect - github.com/charmbracelet/x/cellbuf v0.0.13 // indirect - github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect - github.com/charmbracelet/x/term v0.2.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/go-test/deep v1.1.1 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect - github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/termenv v0.16.0 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/onsi/gomega v1.38.2 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/spf13/pflag v1.0.10 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect -) - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen diff --git a/go.sum b/go.sum deleted file mode 100644 index b3a8919..0000000 --- a/go.sum +++ /dev/null @@ -1,208 +0,0 @@ -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= -github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= -github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= -github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= -github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= -github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= -github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= -github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws= -github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7/go.mod h1:ISC1gtLcVilLOf23wvTfoQuYbW2q0JevFxPfUzZ9Ybw= -github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU= -github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= -github.com/charmbracelet/huh v0.8.0 h1:Xz/Pm2h64cXQZn/Jvele4J3r7DDiqFCNIVteYukxDvY= -github.com/charmbracelet/huh v0.8.0/go.mod h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= -github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0= -github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= -github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= -github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= -github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= -github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= -github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA= -github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= -github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= -github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= -github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= -github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= -github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= -github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= -github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI= -github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4= -github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= -github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= -github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= -github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c h1:EMwsP/vaHQDLhAX1kNIng5mHEhg+CkS18m0AL825n6U= -github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c/go.mod h1:lHwJo6jMevQL9tNpW6vLyhkK13bYHBcoh9tUakMhbnE= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= -github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= -github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= -github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= -github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 h1:5vHNY1uuPBRBWqB2Dp0G7YB03phxLQZupZTIZaeorjc= -github.com/oapi-codegen/oapi-codegen/v2 v2.5.1/go.mod h1:ro0npU1BWkcGpCgGD9QwPp44l5OIZ94tB3eabnT7DjQ= -github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= -github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= -github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= -github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= -github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= -github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= -github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= -github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= -github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/api/client.gen.go b/internal/api/client.gen.go deleted file mode 100644 index 25c0bae..0000000 --- a/internal/api/client.gen.go +++ /dev/null @@ -1,5883 +0,0 @@ -// Package api provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. -package api - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" - - "gopkg.in/yaml.v2" - - "github.com/oapi-codegen/runtime" -) - -const ( - BearerAuthScopes = "BearerAuth.Scopes" -) - -// Defines values for KaasInfoStatus. -const ( - DEGRADED KaasInfoStatus = "DEGRADED" - DELETING KaasInfoStatus = "DELETING" - ERROR KaasInfoStatus = "ERROR" - PROVISIONING KaasInfoStatus = "PROVISIONING" - RECONCILING KaasInfoStatus = "RECONCILING" - RUNNING KaasInfoStatus = "RUNNING" -) - -// Defines values for RegistryCredentialType. -const ( - RegistryCredentialTypeBasic RegistryCredentialType = "basic" - RegistryCredentialTypeOauth RegistryCredentialType = "oauth" - RegistryCredentialTypeToken RegistryCredentialType = "token" -) - -// Defines values for TemplateRegistryProxyMode. -const ( - TemplateRegistryProxyModeAlways TemplateRegistryProxyMode = "always" - TemplateRegistryProxyModeAuto TemplateRegistryProxyMode = "auto" - TemplateRegistryProxyModeLessThannil TemplateRegistryProxyMode = "" - TemplateRegistryProxyModeNever TemplateRegistryProxyMode = "never" -) - -// Defines values for TemplateDetailRegistryProxyMode. -const ( - TemplateDetailRegistryProxyModeAlways TemplateDetailRegistryProxyMode = "always" - TemplateDetailRegistryProxyModeAuto TemplateDetailRegistryProxyMode = "auto" - TemplateDetailRegistryProxyModeLessThannil TemplateDetailRegistryProxyMode = "" - TemplateDetailRegistryProxyModeNever TemplateDetailRegistryProxyMode = "never" -) - -// Defines values for PostV1RegistryCredentialsJSONBodyType. -const ( - PostV1RegistryCredentialsJSONBodyTypeBasic PostV1RegistryCredentialsJSONBodyType = "basic" - PostV1RegistryCredentialsJSONBodyTypeOauth PostV1RegistryCredentialsJSONBodyType = "oauth" - PostV1RegistryCredentialsJSONBodyTypeToken PostV1RegistryCredentialsJSONBodyType = "token" -) - -// Defines values for PostV1TemplatesJSONBodyRegistryProxyMode. -const ( - PostV1TemplatesJSONBodyRegistryProxyModeAlways PostV1TemplatesJSONBodyRegistryProxyMode = "always" - PostV1TemplatesJSONBodyRegistryProxyModeAuto PostV1TemplatesJSONBodyRegistryProxyMode = "auto" - PostV1TemplatesJSONBodyRegistryProxyModeNever PostV1TemplatesJSONBodyRegistryProxyMode = "never" -) - -// Defines values for PatchV1TemplatesIdJSONBodyRegistryProxyMode. -const ( - PatchV1TemplatesIdJSONBodyRegistryProxyModeAlways PatchV1TemplatesIdJSONBodyRegistryProxyMode = "always" - PatchV1TemplatesIdJSONBodyRegistryProxyModeAuto PatchV1TemplatesIdJSONBodyRegistryProxyMode = "auto" - PatchV1TemplatesIdJSONBodyRegistryProxyModeNever PatchV1TemplatesIdJSONBodyRegistryProxyMode = "never" -) - -// ApiToken defines model for ApiToken. -type ApiToken struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - - // ExpiresAt Unix timestamp (seconds), null if never - ExpiresAt *float32 `json:"expires_at"` - Id string `json:"id"` - - // LastUsedAt Unix timestamp (seconds) of last use - LastUsedAt *float32 `json:"last_used_at"` - Name string `json:"name"` - Prefix string `json:"prefix"` -} - -// ApiTokenList defines model for ApiTokenList. -type ApiTokenList struct { - Data []ApiToken `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// Cluster defines model for Cluster. -type Cluster struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - Id string `json:"id"` - - // Kaas Present if cluster is KaaS-managed - Kaas *KaasInfo `json:"kaas"` - Name string `json:"name"` - RegionId string `json:"region_id"` - WorkspaceId string `json:"workspace_id"` -} - -// ClusterList defines model for ClusterList. -type ClusterList struct { - Data []Cluster `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// CreatedToken defines model for CreatedToken. -type CreatedToken struct { - Id string `json:"id"` - Name string `json:"name"` - - // Token The full token. This is shown only once — store it securely. - Token string `json:"token"` -} - -// Error defines model for Error. -type Error struct { - Error struct { - Code string `json:"code"` - Details interface{} `json:"details"` - Message string `json:"message"` - - // Param The request field that caused the error - Param *string `json:"param,omitempty"` - Suggestion *string `json:"suggestion,omitempty"` - } `json:"error"` -} - -// HelmSource defines model for HelmSource. -type HelmSource struct { - Chart HelmSourceChart `json:"chart"` - Id string `json:"id"` - Metadata *map[string]*interface{} `json:"metadata,omitempty"` - Values *map[string]*interface{} `json:"values,omitempty"` -} - -// HelmSourceChart defines model for HelmSourceChart. -type HelmSourceChart struct { - Chart *string `json:"chart,omitempty"` - Path *string `json:"path,omitempty"` - RepoUrl string `json:"repo_url"` - TargetRevision string `json:"target_revision"` -} - -// Install defines model for Install. -type Install struct { - ClusterId string `json:"cluster_id"` - - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - Id string `json:"id"` - Name *string `json:"name"` - - // ProductId Set for product-based installs - ProductId *string `json:"product_id"` - - // TemplateId Template driving this install - TemplateId *string `json:"template_id"` - WorkspaceId string `json:"workspace_id"` -} - -// InstallList defines model for InstallList. -type InstallList struct { - Data []Install `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// KaasInfo Present if cluster is KaaS-managed -type KaasInfo struct { - Status KaasInfoStatus `json:"status"` - StatusMessage *string `json:"status_message"` - Version string `json:"version"` -} - -// KaasInfoStatus defines model for KaasInfo.Status. -type KaasInfoStatus string - -// Pagination defines model for Pagination. -type Pagination struct { - // Cursor Cursor for next page, null if no more - Cursor *string `json:"cursor"` - HasMore bool `json:"has_more"` -} - -// Pod defines model for Pod. -type Pod struct { - Containers []string `json:"containers"` - Name string `json:"name"` -} - -// Product defines model for Product. -type Product struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - Id string `json:"id"` - Name string `json:"name"` - Settings *struct { - CustomDescription *string `json:"custom_description,omitempty"` - CustomImage *string `json:"custom_image,omitempty"` - ShowSources *bool `json:"show_sources,omitempty"` - } `json:"settings"` - TemplateId string `json:"template_id"` - WorkspaceId string `json:"workspace_id"` -} - -// ProductList defines model for ProductList. -type ProductList struct { - Data []Product `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// Region defines model for Region. -type Region struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - - // Icon Icon URL - Icon *string `json:"icon"` - Id string `json:"id"` - Name string `json:"name"` - WorkspaceId string `json:"workspace_id"` -} - -// RegionList defines model for RegionList. -type RegionList struct { - Data []Region `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// RegistryCredential defines model for RegistryCredential. -type RegistryCredential struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - Id string `json:"id"` - - // IsActive Whether the credential is active - IsActive bool `json:"is_active"` - - // LastUsedAt Unix timestamp (seconds) - LastUsedAt *float32 `json:"last_used_at"` - Name string `json:"name"` - RegistryUrl string `json:"registry_url"` - - // Type Auth type - Type RegistryCredentialType `json:"type"` -} - -// RegistryCredentialType Auth type -type RegistryCredentialType string - -// RegistryCredentialList defines model for RegistryCredentialList. -type RegistryCredentialList struct { - Data []RegistryCredential `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// Template defines model for Template. -type Template struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - Id string `json:"id"` - Name string `json:"name"` - RegistryProxyMode *TemplateRegistryProxyMode `json:"registry_proxy_mode"` - WorkspaceId string `json:"workspace_id"` -} - -// TemplateRegistryProxyMode defines model for Template.RegistryProxyMode. -type TemplateRegistryProxyMode string - -// TemplateDetail defines model for TemplateDetail. -type TemplateDetail struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - HelmSources []HelmSource `json:"helm_sources"` - Id string `json:"id"` - Name string `json:"name"` - RegistryProxyMode *TemplateDetailRegistryProxyMode `json:"registry_proxy_mode"` - WorkspaceId string `json:"workspace_id"` -} - -// TemplateDetailRegistryProxyMode defines model for TemplateDetail.RegistryProxyMode. -type TemplateDetailRegistryProxyMode string - -// TemplateList defines model for TemplateList. -type TemplateList struct { - Data []Template `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// Workspace defines model for Workspace. -type Workspace struct { - // CreatedAt Unix timestamp (seconds) - CreatedAt float32 `json:"created_at"` - Icon *string `json:"icon"` - Id string `json:"id"` - Name string `json:"name"` -} - -// WorkspaceList defines model for WorkspaceList. -type WorkspaceList struct { - Data []Workspace `json:"data"` - Pagination Pagination `json:"pagination"` -} - -// GetV1ClustersParams defines parameters for GetV1Clusters. -type GetV1ClustersParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PatchV1ClustersIdJSONBody defines parameters for PatchV1ClustersId. -type PatchV1ClustersIdJSONBody struct { - Name *string `json:"name,omitempty"` - - // RegionId Region ID - RegionId *string `json:"region_id,omitempty"` -} - -// GetV1InstallsParams defines parameters for GetV1Installs. -type GetV1InstallsParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PostV1InstallsJSONBody defines parameters for PostV1Installs. -type PostV1InstallsJSONBody struct { - // Overrides Initial value overrides per helm source - Overrides *[]struct { - // TemplateHelmSourceId Helm source ID to override - TemplateHelmSourceId string `json:"template_helm_source_id"` - - // Values Helm values - Values map[string]*interface{} `json:"values"` - } `json:"overrides,omitempty"` - - // ProductId Product ID - ProductId string `json:"product_id"` - - // RegionId Region ID - RegionId string `json:"region_id"` -} - -// PostV1InstallsParams defines parameters for PostV1Installs. -type PostV1InstallsParams struct { - // IdempotencyKey Unique key to prevent duplicate operations. If the same key is sent again, the existing workflow is returned instead of creating a new one. - IdempotencyKey *string `json:"idempotency-key,omitempty"` -} - -// PostV1InstallsStandaloneJSONBody defines parameters for PostV1InstallsStandalone. -type PostV1InstallsStandaloneJSONBody struct { - // ClusterIds Cluster IDs to deploy to - ClusterIds []string `json:"cluster_ids"` - HelmSources []struct { - Chart struct { - Chart *string `json:"chart,omitempty"` - Path *string `json:"path,omitempty"` - RepoUrl string `json:"repo_url"` - TargetRevision string `json:"target_revision"` - } `json:"chart"` - Metadata *map[string]*interface{} `json:"metadata,omitempty"` - Values *map[string]*interface{} `json:"values,omitempty"` - } `json:"helm_sources"` - Name string `json:"name"` -} - -// PostV1InstallsStandaloneParams defines parameters for PostV1InstallsStandalone. -type PostV1InstallsStandaloneParams struct { - // IdempotencyKey Unique key to prevent duplicate operations. If the same key is sent again, the existing workflow is returned instead of creating a new one. - IdempotencyKey *string `json:"idempotency-key,omitempty"` -} - -// GetV1InstallsIdLogsParams defines parameters for GetV1InstallsIdLogs. -type GetV1InstallsIdLogsParams struct { - // Pod Pod name (all pods if omitted) - Pod *string `form:"pod,omitempty" json:"pod,omitempty"` - - // Container Container name - Container *string `form:"container,omitempty" json:"container,omitempty"` - - // Follow Follow log output - Follow *bool `form:"follow,omitempty" json:"follow,omitempty"` - - // Tail Lines to tail - Tail *int `form:"tail,omitempty" json:"tail,omitempty"` - - // SinceSeconds Only return logs newer than this many seconds - SinceSeconds *int `form:"since_seconds,omitempty" json:"since_seconds,omitempty"` -} - -// PatchV1InstallsIdOverridesJSONBody defines parameters for PatchV1InstallsIdOverrides. -type PatchV1InstallsIdOverridesJSONBody struct { - Updates []struct { - // TemplateHelmSourceId Helm source ID - TemplateHelmSourceId string `json:"template_helm_source_id"` - - // Values Override values - Values map[string]*interface{} `json:"values"` - } `json:"updates"` -} - -// PatchV1InstallsIdValuesJSONBody defines parameters for PatchV1InstallsIdValues. -type PatchV1InstallsIdValuesJSONBody struct { - Updates []struct { - // TemplateHelmSourceId Helm source ID - TemplateHelmSourceId string `json:"template_helm_source_id"` - - // Values Helm values - Values map[string]*interface{} `json:"values"` - } `json:"updates"` -} - -// GetV1ProductsParams defines parameters for GetV1Products. -type GetV1ProductsParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PostV1ProductsJSONBody defines parameters for PostV1Products. -type PostV1ProductsJSONBody struct { - // ClusterIds Cluster IDs to deploy to - ClusterIds []string `json:"cluster_ids"` - Name string `json:"name"` - Settings *struct { - CustomDescription *string `json:"custom_description,omitempty"` - CustomImage *string `json:"custom_image,omitempty"` - ShowSources *bool `json:"show_sources,omitempty"` - } `json:"settings,omitempty"` - Sources []struct { - Chart struct { - Chart *string `json:"chart,omitempty"` - Path *string `json:"path,omitempty"` - RepoUrl string `json:"repo_url"` - TargetRevision string `json:"target_revision"` - } `json:"chart"` - Metadata *map[string]*interface{} `json:"metadata,omitempty"` - Values *map[string]*interface{} `json:"values,omitempty"` - } `json:"sources"` - StripePriceIds *[]string `json:"stripe_price_ids,omitempty"` -} - -// PatchV1ProductsIdJSONBody defines parameters for PatchV1ProductsId. -type PatchV1ProductsIdJSONBody struct { - ClusterIds []string `json:"cluster_ids"` - Name string `json:"name"` - Settings *struct { - CustomDescription *string `json:"custom_description,omitempty"` - CustomImage *string `json:"custom_image,omitempty"` - ShowSources *bool `json:"show_sources,omitempty"` - } `json:"settings,omitempty"` - Sources []struct { - Chart struct { - Chart *string `json:"chart,omitempty"` - Path *string `json:"path,omitempty"` - RepoUrl string `json:"repo_url"` - TargetRevision string `json:"target_revision"` - } `json:"chart"` - Metadata *map[string]*interface{} `json:"metadata,omitempty"` - Values *map[string]*interface{} `json:"values,omitempty"` - } `json:"sources"` - StripePriceIds *[]string `json:"stripe_price_ids,omitempty"` -} - -// GetV1RegionsParams defines parameters for GetV1Regions. -type GetV1RegionsParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PostV1RegionsJSONBody defines parameters for PostV1Regions. -type PostV1RegionsJSONBody struct { - // Icon Icon URL - Icon *string `json:"icon,omitempty"` - Name string `json:"name"` -} - -// GetV1RegistryCredentialsParams defines parameters for GetV1RegistryCredentials. -type GetV1RegistryCredentialsParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PostV1RegistryCredentialsJSONBody defines parameters for PostV1RegistryCredentials. -type PostV1RegistryCredentialsJSONBody struct { - // Credentials Auth credentials (type-dependent) - Credentials struct { - ClientId *string `json:"client_id,omitempty"` - ClientSecret *string `json:"client_secret,omitempty"` - Password *string `json:"password,omitempty"` - Token *string `json:"token,omitempty"` - TokenUrl *string `json:"token_url,omitempty"` - Username *string `json:"username,omitempty"` - } `json:"credentials"` - Name string `json:"name"` - RegistryUrl string `json:"registry_url"` - - // Type Auth type - Type PostV1RegistryCredentialsJSONBodyType `json:"type"` -} - -// PostV1RegistryCredentialsJSONBodyType defines parameters for PostV1RegistryCredentials. -type PostV1RegistryCredentialsJSONBodyType string - -// GetV1TemplatesParams defines parameters for GetV1Templates. -type GetV1TemplatesParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PostV1TemplatesJSONBody defines parameters for PostV1Templates. -type PostV1TemplatesJSONBody struct { - Name string `json:"name"` - RegistryProxyMode *PostV1TemplatesJSONBodyRegistryProxyMode `json:"registry_proxy_mode,omitempty"` - Sources []struct { - Chart struct { - Chart *string `json:"chart,omitempty"` - Path *string `json:"path,omitempty"` - RepoUrl string `json:"repo_url"` - TargetRevision string `json:"target_revision"` - } `json:"chart"` - Metadata *struct { - ArtifactHubHelmPackage *map[string]*interface{} `json:"artifact_hub_helm_package,omitempty"` - AutoDeploy *bool `json:"auto_deploy,omitempty"` - Image *struct { - Github *struct { - Repository *struct { - FullName string `json:"full_name"` - HtmlUrl string `json:"html_url"` - Id float32 `json:"id"` - Name string `json:"name"` - Owner struct { - AvatarUrl string `json:"avatar_url"` - HtmlUrl string `json:"html_url"` - Id float32 `json:"id"` - Login string `json:"login"` - Type string `json:"type"` - } `json:"owner"` - } `json:"repository,omitempty"` - WorkflowRunId *string `json:"workflow_run_id,omitempty"` - } `json:"github,omitempty"` - Tag string `json:"tag"` - Url string `json:"url"` - } `json:"image,omitempty"` - } `json:"metadata,omitempty"` - Values *map[string]*interface{} `json:"values,omitempty"` - } `json:"sources"` -} - -// PostV1TemplatesJSONBodyRegistryProxyMode defines parameters for PostV1Templates. -type PostV1TemplatesJSONBodyRegistryProxyMode string - -// PatchV1TemplatesIdJSONBody defines parameters for PatchV1TemplatesId. -type PatchV1TemplatesIdJSONBody struct { - Name *string `json:"name,omitempty"` - RegistryProxyMode *PatchV1TemplatesIdJSONBodyRegistryProxyMode `json:"registry_proxy_mode,omitempty"` - Sources *[]struct { - Chart struct { - Chart *string `json:"chart,omitempty"` - Path *string `json:"path,omitempty"` - RepoUrl string `json:"repo_url"` - TargetRevision string `json:"target_revision"` - } `json:"chart"` - Metadata *struct { - ArtifactHubHelmPackage *map[string]*interface{} `json:"artifact_hub_helm_package,omitempty"` - AutoDeploy *bool `json:"auto_deploy,omitempty"` - Image *struct { - Github *struct { - Repository *struct { - FullName string `json:"full_name"` - HtmlUrl string `json:"html_url"` - Id float32 `json:"id"` - Name string `json:"name"` - Owner struct { - AvatarUrl string `json:"avatar_url"` - HtmlUrl string `json:"html_url"` - Id float32 `json:"id"` - Login string `json:"login"` - Type string `json:"type"` - } `json:"owner"` - } `json:"repository,omitempty"` - WorkflowRunId *string `json:"workflow_run_id,omitempty"` - } `json:"github,omitempty"` - Tag string `json:"tag"` - Url string `json:"url"` - } `json:"image,omitempty"` - } `json:"metadata,omitempty"` - Values *map[string]*interface{} `json:"values,omitempty"` - } `json:"sources,omitempty"` -} - -// PatchV1TemplatesIdJSONBodyRegistryProxyMode defines parameters for PatchV1TemplatesId. -type PatchV1TemplatesIdJSONBodyRegistryProxyMode string - -// GetV1UserTokensParams defines parameters for GetV1UserTokens. -type GetV1UserTokensParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PostV1UserTokensJSONBody defines parameters for PostV1UserTokens. -type PostV1UserTokensJSONBody struct { - // ExpiresAt Unix timestamp (seconds) when the token expires. Omit for no expiry. - ExpiresAt *int `json:"expires_at,omitempty"` - - // Name Human-readable name for the token - Name string `json:"name"` -} - -// GetV1WorkspacesParams defines parameters for GetV1Workspaces. -type GetV1WorkspacesParams struct { - // Cursor Pagination cursor from previous response - Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` - - // Limit Items per page (1-100) - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// PatchV1ClustersIdJSONRequestBody defines body for PatchV1ClustersId for application/json ContentType. -type PatchV1ClustersIdJSONRequestBody PatchV1ClustersIdJSONBody - -// PostV1InstallsJSONRequestBody defines body for PostV1Installs for application/json ContentType. -type PostV1InstallsJSONRequestBody PostV1InstallsJSONBody - -// PostV1InstallsStandaloneJSONRequestBody defines body for PostV1InstallsStandalone for application/json ContentType. -type PostV1InstallsStandaloneJSONRequestBody PostV1InstallsStandaloneJSONBody - -// PatchV1InstallsIdOverridesJSONRequestBody defines body for PatchV1InstallsIdOverrides for application/json ContentType. -type PatchV1InstallsIdOverridesJSONRequestBody PatchV1InstallsIdOverridesJSONBody - -// PatchV1InstallsIdValuesJSONRequestBody defines body for PatchV1InstallsIdValues for application/json ContentType. -type PatchV1InstallsIdValuesJSONRequestBody PatchV1InstallsIdValuesJSONBody - -// PostV1ProductsJSONRequestBody defines body for PostV1Products for application/json ContentType. -type PostV1ProductsJSONRequestBody PostV1ProductsJSONBody - -// PatchV1ProductsIdJSONRequestBody defines body for PatchV1ProductsId for application/json ContentType. -type PatchV1ProductsIdJSONRequestBody PatchV1ProductsIdJSONBody - -// PostV1RegionsJSONRequestBody defines body for PostV1Regions for application/json ContentType. -type PostV1RegionsJSONRequestBody PostV1RegionsJSONBody - -// PostV1RegistryCredentialsJSONRequestBody defines body for PostV1RegistryCredentials for application/json ContentType. -type PostV1RegistryCredentialsJSONRequestBody PostV1RegistryCredentialsJSONBody - -// PostV1TemplatesJSONRequestBody defines body for PostV1Templates for application/json ContentType. -type PostV1TemplatesJSONRequestBody PostV1TemplatesJSONBody - -// PatchV1TemplatesIdJSONRequestBody defines body for PatchV1TemplatesId for application/json ContentType. -type PatchV1TemplatesIdJSONRequestBody PatchV1TemplatesIdJSONBody - -// PostV1UserTokensJSONRequestBody defines body for PostV1UserTokens for application/json ContentType. -type PostV1UserTokensJSONRequestBody PostV1UserTokensJSONBody - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// Doer performs HTTP requests. -// -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) -} - -// Client which conforms to the OpenAPI3 specification for this service. -type Client struct { - // The endpoint of the server conforming to this interface, with scheme, - // https://api.deepmap.com for example. This can contain a path relative - // to the server, such as https://api.deepmap.com/dev-test, and all the - // paths in the swagger spec will be appended to the server. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A list of callbacks for modifying requests which are generated before sending over - // the network. - RequestEditors []RequestEditorFn -} - -// ClientOption allows setting custom parameters during construction -type ClientOption func(*Client) error - -// Creates a new Client, with reasonable defaults -func NewClient(server string, opts ...ClientOption) (*Client, error) { - // create a client with sane default values - client := Client{ - Server: server, - } - // mutate client and add all optional params - for _, o := range opts { - if err := o(&client); err != nil { - return nil, err - } - } - // ensure the server URL always has a trailing slash - if !strings.HasSuffix(client.Server, "/") { - client.Server += "/" - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = &http.Client{} - } - return &client, nil -} - -// WithHTTPClient allows overriding the default Doer, which is -// automatically created using http.Client. This is useful for tests. -func WithHTTPClient(doer HttpRequestDoer) ClientOption { - return func(c *Client) error { - c.Client = doer - return nil - } -} - -// WithRequestEditorFn allows setting up a callback function, which will be -// called right before sending the request. This can be used to mutate the request. -func WithRequestEditorFn(fn RequestEditorFn) ClientOption { - return func(c *Client) error { - c.RequestEditors = append(c.RequestEditors, fn) - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // GetV1Clusters request - GetV1Clusters(ctx context.Context, params *GetV1ClustersParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // DeleteV1ClustersId request - DeleteV1ClustersId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1ClustersId request - GetV1ClustersId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PatchV1ClustersIdWithBody request with any body - PatchV1ClustersIdWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PatchV1ClustersId(ctx context.Context, id string, body PatchV1ClustersIdJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1ClustersIdKubeconfig request - GetV1ClustersIdKubeconfig(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1Installs request - GetV1Installs(ctx context.Context, params *GetV1InstallsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1InstallsWithBody request with any body - PostV1InstallsWithBody(ctx context.Context, params *PostV1InstallsParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1Installs(ctx context.Context, params *PostV1InstallsParams, body PostV1InstallsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1InstallsStandaloneWithBody request with any body - PostV1InstallsStandaloneWithBody(ctx context.Context, params *PostV1InstallsStandaloneParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1InstallsStandalone(ctx context.Context, params *PostV1InstallsStandaloneParams, body PostV1InstallsStandaloneJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // DeleteV1InstallsId request - DeleteV1InstallsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1InstallsId request - GetV1InstallsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1InstallsIdLogs request - GetV1InstallsIdLogs(ctx context.Context, id string, params *GetV1InstallsIdLogsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PatchV1InstallsIdOverridesWithBody request with any body - PatchV1InstallsIdOverridesWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PatchV1InstallsIdOverrides(ctx context.Context, id string, body PatchV1InstallsIdOverridesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1InstallsIdPods request - GetV1InstallsIdPods(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PatchV1InstallsIdValuesWithBody request with any body - PatchV1InstallsIdValuesWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PatchV1InstallsIdValues(ctx context.Context, id string, body PatchV1InstallsIdValuesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1Products request - GetV1Products(ctx context.Context, params *GetV1ProductsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1ProductsWithBody request with any body - PostV1ProductsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1Products(ctx context.Context, body PostV1ProductsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // DeleteV1ProductsId request - DeleteV1ProductsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1ProductsId request - GetV1ProductsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PatchV1ProductsIdWithBody request with any body - PatchV1ProductsIdWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PatchV1ProductsId(ctx context.Context, id string, body PatchV1ProductsIdJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1Regions request - GetV1Regions(ctx context.Context, params *GetV1RegionsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1RegionsWithBody request with any body - PostV1RegionsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1Regions(ctx context.Context, body PostV1RegionsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1RegistryCredentials request - GetV1RegistryCredentials(ctx context.Context, params *GetV1RegistryCredentialsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1RegistryCredentialsWithBody request with any body - PostV1RegistryCredentialsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1RegistryCredentials(ctx context.Context, body PostV1RegistryCredentialsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // DeleteV1RegistryCredentialsId request - DeleteV1RegistryCredentialsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1Templates request - GetV1Templates(ctx context.Context, params *GetV1TemplatesParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1TemplatesWithBody request with any body - PostV1TemplatesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1Templates(ctx context.Context, body PostV1TemplatesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // DeleteV1TemplatesId request - DeleteV1TemplatesId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1TemplatesId request - GetV1TemplatesId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PatchV1TemplatesIdWithBody request with any body - PatchV1TemplatesIdWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PatchV1TemplatesId(ctx context.Context, id string, body PatchV1TemplatesIdJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1UserTokens request - GetV1UserTokens(ctx context.Context, params *GetV1UserTokensParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PostV1UserTokensWithBody request with any body - PostV1UserTokensWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PostV1UserTokens(ctx context.Context, body PostV1UserTokensJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // DeleteV1UserTokensId request - DeleteV1UserTokensId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1Workspaces request - GetV1Workspaces(ctx context.Context, params *GetV1WorkspacesParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetV1WorkspacesId request - GetV1WorkspacesId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -func (c *Client) GetV1Clusters(ctx context.Context, params *GetV1ClustersParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1ClustersRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) DeleteV1ClustersId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteV1ClustersIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1ClustersId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1ClustersIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1ClustersIdWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1ClustersIdRequestWithBody(c.Server, id, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1ClustersId(ctx context.Context, id string, body PatchV1ClustersIdJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1ClustersIdRequest(c.Server, id, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1ClustersIdKubeconfig(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1ClustersIdKubeconfigRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1Installs(ctx context.Context, params *GetV1InstallsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1InstallsRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1InstallsWithBody(ctx context.Context, params *PostV1InstallsParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1InstallsRequestWithBody(c.Server, params, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1Installs(ctx context.Context, params *PostV1InstallsParams, body PostV1InstallsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1InstallsRequest(c.Server, params, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1InstallsStandaloneWithBody(ctx context.Context, params *PostV1InstallsStandaloneParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1InstallsStandaloneRequestWithBody(c.Server, params, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1InstallsStandalone(ctx context.Context, params *PostV1InstallsStandaloneParams, body PostV1InstallsStandaloneJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1InstallsStandaloneRequest(c.Server, params, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) DeleteV1InstallsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteV1InstallsIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1InstallsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1InstallsIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1InstallsIdLogs(ctx context.Context, id string, params *GetV1InstallsIdLogsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1InstallsIdLogsRequest(c.Server, id, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1InstallsIdOverridesWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1InstallsIdOverridesRequestWithBody(c.Server, id, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1InstallsIdOverrides(ctx context.Context, id string, body PatchV1InstallsIdOverridesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1InstallsIdOverridesRequest(c.Server, id, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1InstallsIdPods(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1InstallsIdPodsRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1InstallsIdValuesWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1InstallsIdValuesRequestWithBody(c.Server, id, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1InstallsIdValues(ctx context.Context, id string, body PatchV1InstallsIdValuesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1InstallsIdValuesRequest(c.Server, id, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1Products(ctx context.Context, params *GetV1ProductsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1ProductsRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1ProductsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1ProductsRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1Products(ctx context.Context, body PostV1ProductsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1ProductsRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) DeleteV1ProductsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteV1ProductsIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1ProductsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1ProductsIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1ProductsIdWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1ProductsIdRequestWithBody(c.Server, id, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1ProductsId(ctx context.Context, id string, body PatchV1ProductsIdJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1ProductsIdRequest(c.Server, id, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1Regions(ctx context.Context, params *GetV1RegionsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1RegionsRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1RegionsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1RegionsRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1Regions(ctx context.Context, body PostV1RegionsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1RegionsRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1RegistryCredentials(ctx context.Context, params *GetV1RegistryCredentialsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1RegistryCredentialsRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1RegistryCredentialsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1RegistryCredentialsRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1RegistryCredentials(ctx context.Context, body PostV1RegistryCredentialsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1RegistryCredentialsRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) DeleteV1RegistryCredentialsId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteV1RegistryCredentialsIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1Templates(ctx context.Context, params *GetV1TemplatesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1TemplatesRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1TemplatesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1TemplatesRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1Templates(ctx context.Context, body PostV1TemplatesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1TemplatesRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) DeleteV1TemplatesId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteV1TemplatesIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1TemplatesId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1TemplatesIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1TemplatesIdWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1TemplatesIdRequestWithBody(c.Server, id, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchV1TemplatesId(ctx context.Context, id string, body PatchV1TemplatesIdJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchV1TemplatesIdRequest(c.Server, id, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1UserTokens(ctx context.Context, params *GetV1UserTokensParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1UserTokensRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1UserTokensWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1UserTokensRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PostV1UserTokens(ctx context.Context, body PostV1UserTokensJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPostV1UserTokensRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) DeleteV1UserTokensId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteV1UserTokensIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1Workspaces(ctx context.Context, params *GetV1WorkspacesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1WorkspacesRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetV1WorkspacesId(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV1WorkspacesIdRequest(c.Server, id) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -// NewGetV1ClustersRequest generates requests for GetV1Clusters -func NewGetV1ClustersRequest(server string, params *GetV1ClustersParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/clusters") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewDeleteV1ClustersIdRequest generates requests for DeleteV1ClustersId -func NewDeleteV1ClustersIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/clusters/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1ClustersIdRequest generates requests for GetV1ClustersId -func NewGetV1ClustersIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/clusters/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPatchV1ClustersIdRequest calls the generic PatchV1ClustersId builder with application/json body -func NewPatchV1ClustersIdRequest(server string, id string, body PatchV1ClustersIdJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPatchV1ClustersIdRequestWithBody(server, id, "application/json", bodyReader) -} - -// NewPatchV1ClustersIdRequestWithBody generates requests for PatchV1ClustersId with any type of body -func NewPatchV1ClustersIdRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/clusters/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PATCH", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewGetV1ClustersIdKubeconfigRequest generates requests for GetV1ClustersIdKubeconfig -func NewGetV1ClustersIdKubeconfigRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/clusters/%s/kubeconfig", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1InstallsRequest generates requests for GetV1Installs -func NewGetV1InstallsRequest(server string, params *GetV1InstallsParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostV1InstallsRequest calls the generic PostV1Installs builder with application/json body -func NewPostV1InstallsRequest(server string, params *PostV1InstallsParams, body PostV1InstallsJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1InstallsRequestWithBody(server, params, "application/json", bodyReader) -} - -// NewPostV1InstallsRequestWithBody generates requests for PostV1Installs with any type of body -func NewPostV1InstallsRequestWithBody(server string, params *PostV1InstallsParams, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - if params != nil { - - if params.IdempotencyKey != nil { - var headerParam0 string - - headerParam0, err = runtime.StyleParamWithLocation("simple", false, "idempotency-key", runtime.ParamLocationHeader, *params.IdempotencyKey) - if err != nil { - return nil, err - } - - req.Header.Set("idempotency-key", headerParam0) - } - - } - - return req, nil -} - -// NewPostV1InstallsStandaloneRequest calls the generic PostV1InstallsStandalone builder with application/json body -func NewPostV1InstallsStandaloneRequest(server string, params *PostV1InstallsStandaloneParams, body PostV1InstallsStandaloneJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1InstallsStandaloneRequestWithBody(server, params, "application/json", bodyReader) -} - -// NewPostV1InstallsStandaloneRequestWithBody generates requests for PostV1InstallsStandalone with any type of body -func NewPostV1InstallsStandaloneRequestWithBody(server string, params *PostV1InstallsStandaloneParams, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/standalone") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - if params != nil { - - if params.IdempotencyKey != nil { - var headerParam0 string - - headerParam0, err = runtime.StyleParamWithLocation("simple", false, "idempotency-key", runtime.ParamLocationHeader, *params.IdempotencyKey) - if err != nil { - return nil, err - } - - req.Header.Set("idempotency-key", headerParam0) - } - - } - - return req, nil -} - -// NewDeleteV1InstallsIdRequest generates requests for DeleteV1InstallsId -func NewDeleteV1InstallsIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1InstallsIdRequest generates requests for GetV1InstallsId -func NewGetV1InstallsIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1InstallsIdLogsRequest generates requests for GetV1InstallsIdLogs -func NewGetV1InstallsIdLogsRequest(server string, id string, params *GetV1InstallsIdLogsParams) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/%s/logs", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Pod != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "pod", runtime.ParamLocationQuery, *params.Pod); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Container != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "container", runtime.ParamLocationQuery, *params.Container); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Follow != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "follow", runtime.ParamLocationQuery, *params.Follow); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Tail != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tail", runtime.ParamLocationQuery, *params.Tail); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.SinceSeconds != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "since_seconds", runtime.ParamLocationQuery, *params.SinceSeconds); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPatchV1InstallsIdOverridesRequest calls the generic PatchV1InstallsIdOverrides builder with application/json body -func NewPatchV1InstallsIdOverridesRequest(server string, id string, body PatchV1InstallsIdOverridesJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPatchV1InstallsIdOverridesRequestWithBody(server, id, "application/json", bodyReader) -} - -// NewPatchV1InstallsIdOverridesRequestWithBody generates requests for PatchV1InstallsIdOverrides with any type of body -func NewPatchV1InstallsIdOverridesRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/%s/overrides", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PATCH", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewGetV1InstallsIdPodsRequest generates requests for GetV1InstallsIdPods -func NewGetV1InstallsIdPodsRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/%s/pods", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPatchV1InstallsIdValuesRequest calls the generic PatchV1InstallsIdValues builder with application/json body -func NewPatchV1InstallsIdValuesRequest(server string, id string, body PatchV1InstallsIdValuesJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPatchV1InstallsIdValuesRequestWithBody(server, id, "application/json", bodyReader) -} - -// NewPatchV1InstallsIdValuesRequestWithBody generates requests for PatchV1InstallsIdValues with any type of body -func NewPatchV1InstallsIdValuesRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/installs/%s/values", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PATCH", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewGetV1ProductsRequest generates requests for GetV1Products -func NewGetV1ProductsRequest(server string, params *GetV1ProductsParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/products") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostV1ProductsRequest calls the generic PostV1Products builder with application/json body -func NewPostV1ProductsRequest(server string, body PostV1ProductsJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1ProductsRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostV1ProductsRequestWithBody generates requests for PostV1Products with any type of body -func NewPostV1ProductsRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/products") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewDeleteV1ProductsIdRequest generates requests for DeleteV1ProductsId -func NewDeleteV1ProductsIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/products/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1ProductsIdRequest generates requests for GetV1ProductsId -func NewGetV1ProductsIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/products/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPatchV1ProductsIdRequest calls the generic PatchV1ProductsId builder with application/json body -func NewPatchV1ProductsIdRequest(server string, id string, body PatchV1ProductsIdJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPatchV1ProductsIdRequestWithBody(server, id, "application/json", bodyReader) -} - -// NewPatchV1ProductsIdRequestWithBody generates requests for PatchV1ProductsId with any type of body -func NewPatchV1ProductsIdRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/products/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PATCH", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewGetV1RegionsRequest generates requests for GetV1Regions -func NewGetV1RegionsRequest(server string, params *GetV1RegionsParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/regions") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostV1RegionsRequest calls the generic PostV1Regions builder with application/json body -func NewPostV1RegionsRequest(server string, body PostV1RegionsJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1RegionsRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostV1RegionsRequestWithBody generates requests for PostV1Regions with any type of body -func NewPostV1RegionsRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/regions") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewGetV1RegistryCredentialsRequest generates requests for GetV1RegistryCredentials -func NewGetV1RegistryCredentialsRequest(server string, params *GetV1RegistryCredentialsParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/registry/credentials") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostV1RegistryCredentialsRequest calls the generic PostV1RegistryCredentials builder with application/json body -func NewPostV1RegistryCredentialsRequest(server string, body PostV1RegistryCredentialsJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1RegistryCredentialsRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostV1RegistryCredentialsRequestWithBody generates requests for PostV1RegistryCredentials with any type of body -func NewPostV1RegistryCredentialsRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/registry/credentials") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewDeleteV1RegistryCredentialsIdRequest generates requests for DeleteV1RegistryCredentialsId -func NewDeleteV1RegistryCredentialsIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/registry/credentials/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1TemplatesRequest generates requests for GetV1Templates -func NewGetV1TemplatesRequest(server string, params *GetV1TemplatesParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/templates") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostV1TemplatesRequest calls the generic PostV1Templates builder with application/json body -func NewPostV1TemplatesRequest(server string, body PostV1TemplatesJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1TemplatesRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostV1TemplatesRequestWithBody generates requests for PostV1Templates with any type of body -func NewPostV1TemplatesRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/templates") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewDeleteV1TemplatesIdRequest generates requests for DeleteV1TemplatesId -func NewDeleteV1TemplatesIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/templates/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1TemplatesIdRequest generates requests for GetV1TemplatesId -func NewGetV1TemplatesIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/templates/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPatchV1TemplatesIdRequest calls the generic PatchV1TemplatesId builder with application/json body -func NewPatchV1TemplatesIdRequest(server string, id string, body PatchV1TemplatesIdJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPatchV1TemplatesIdRequestWithBody(server, id, "application/json", bodyReader) -} - -// NewPatchV1TemplatesIdRequestWithBody generates requests for PatchV1TemplatesId with any type of body -func NewPatchV1TemplatesIdRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/templates/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PATCH", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewGetV1UserTokensRequest generates requests for GetV1UserTokens -func NewGetV1UserTokensRequest(server string, params *GetV1UserTokensParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/user/tokens") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPostV1UserTokensRequest calls the generic PostV1UserTokens builder with application/json body -func NewPostV1UserTokensRequest(server string, body PostV1UserTokensJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPostV1UserTokensRequestWithBody(server, "application/json", bodyReader) -} - -// NewPostV1UserTokensRequestWithBody generates requests for PostV1UserTokens with any type of body -func NewPostV1UserTokensRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/user/tokens") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewDeleteV1UserTokensIdRequest generates requests for DeleteV1UserTokensId -func NewDeleteV1UserTokensIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/user/tokens/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1WorkspacesRequest generates requests for GetV1Workspaces -func NewGetV1WorkspacesRequest(server string, params *GetV1WorkspacesParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/workspaces") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Cursor != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.Limit != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetV1WorkspacesIdRequest generates requests for GetV1WorkspacesId -func NewGetV1WorkspacesIdRequest(server string, id string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v1/workspaces/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { - for _, r := range c.RequestEditors { - if err := r(ctx, req); err != nil { - return err - } - } - for _, r := range additionalEditors { - if err := r(ctx, req); err != nil { - return err - } - } - return nil -} - -// ClientWithResponses builds on ClientInterface to offer response payloads -type ClientWithResponses struct { - ClientInterface -} - -// NewClientWithResponses creates a new ClientWithResponses, which wraps -// Client with return type handling -func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { - client, err := NewClient(server, opts...) - if err != nil { - return nil, err - } - return &ClientWithResponses{client}, nil -} - -// WithBaseURL overrides the baseURL. -func WithBaseURL(baseURL string) ClientOption { - return func(c *Client) error { - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -// ClientWithResponsesInterface is the interface specification for the client with responses above. -type ClientWithResponsesInterface interface { - // GetV1ClustersWithResponse request - GetV1ClustersWithResponse(ctx context.Context, params *GetV1ClustersParams, reqEditors ...RequestEditorFn) (*GetV1ClustersResponse, error) - - // DeleteV1ClustersIdWithResponse request - DeleteV1ClustersIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1ClustersIdResponse, error) - - // GetV1ClustersIdWithResponse request - GetV1ClustersIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1ClustersIdResponse, error) - - // PatchV1ClustersIdWithBodyWithResponse request with any body - PatchV1ClustersIdWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1ClustersIdResponse, error) - - PatchV1ClustersIdWithResponse(ctx context.Context, id string, body PatchV1ClustersIdJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1ClustersIdResponse, error) - - // GetV1ClustersIdKubeconfigWithResponse request - GetV1ClustersIdKubeconfigWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1ClustersIdKubeconfigResponse, error) - - // GetV1InstallsWithResponse request - GetV1InstallsWithResponse(ctx context.Context, params *GetV1InstallsParams, reqEditors ...RequestEditorFn) (*GetV1InstallsResponse, error) - - // PostV1InstallsWithBodyWithResponse request with any body - PostV1InstallsWithBodyWithResponse(ctx context.Context, params *PostV1InstallsParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1InstallsResponse, error) - - PostV1InstallsWithResponse(ctx context.Context, params *PostV1InstallsParams, body PostV1InstallsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1InstallsResponse, error) - - // PostV1InstallsStandaloneWithBodyWithResponse request with any body - PostV1InstallsStandaloneWithBodyWithResponse(ctx context.Context, params *PostV1InstallsStandaloneParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1InstallsStandaloneResponse, error) - - PostV1InstallsStandaloneWithResponse(ctx context.Context, params *PostV1InstallsStandaloneParams, body PostV1InstallsStandaloneJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1InstallsStandaloneResponse, error) - - // DeleteV1InstallsIdWithResponse request - DeleteV1InstallsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1InstallsIdResponse, error) - - // GetV1InstallsIdWithResponse request - GetV1InstallsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1InstallsIdResponse, error) - - // GetV1InstallsIdLogsWithResponse request - GetV1InstallsIdLogsWithResponse(ctx context.Context, id string, params *GetV1InstallsIdLogsParams, reqEditors ...RequestEditorFn) (*GetV1InstallsIdLogsResponse, error) - - // PatchV1InstallsIdOverridesWithBodyWithResponse request with any body - PatchV1InstallsIdOverridesWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdOverridesResponse, error) - - PatchV1InstallsIdOverridesWithResponse(ctx context.Context, id string, body PatchV1InstallsIdOverridesJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdOverridesResponse, error) - - // GetV1InstallsIdPodsWithResponse request - GetV1InstallsIdPodsWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1InstallsIdPodsResponse, error) - - // PatchV1InstallsIdValuesWithBodyWithResponse request with any body - PatchV1InstallsIdValuesWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdValuesResponse, error) - - PatchV1InstallsIdValuesWithResponse(ctx context.Context, id string, body PatchV1InstallsIdValuesJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdValuesResponse, error) - - // GetV1ProductsWithResponse request - GetV1ProductsWithResponse(ctx context.Context, params *GetV1ProductsParams, reqEditors ...RequestEditorFn) (*GetV1ProductsResponse, error) - - // PostV1ProductsWithBodyWithResponse request with any body - PostV1ProductsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1ProductsResponse, error) - - PostV1ProductsWithResponse(ctx context.Context, body PostV1ProductsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1ProductsResponse, error) - - // DeleteV1ProductsIdWithResponse request - DeleteV1ProductsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1ProductsIdResponse, error) - - // GetV1ProductsIdWithResponse request - GetV1ProductsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1ProductsIdResponse, error) - - // PatchV1ProductsIdWithBodyWithResponse request with any body - PatchV1ProductsIdWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1ProductsIdResponse, error) - - PatchV1ProductsIdWithResponse(ctx context.Context, id string, body PatchV1ProductsIdJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1ProductsIdResponse, error) - - // GetV1RegionsWithResponse request - GetV1RegionsWithResponse(ctx context.Context, params *GetV1RegionsParams, reqEditors ...RequestEditorFn) (*GetV1RegionsResponse, error) - - // PostV1RegionsWithBodyWithResponse request with any body - PostV1RegionsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1RegionsResponse, error) - - PostV1RegionsWithResponse(ctx context.Context, body PostV1RegionsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1RegionsResponse, error) - - // GetV1RegistryCredentialsWithResponse request - GetV1RegistryCredentialsWithResponse(ctx context.Context, params *GetV1RegistryCredentialsParams, reqEditors ...RequestEditorFn) (*GetV1RegistryCredentialsResponse, error) - - // PostV1RegistryCredentialsWithBodyWithResponse request with any body - PostV1RegistryCredentialsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1RegistryCredentialsResponse, error) - - PostV1RegistryCredentialsWithResponse(ctx context.Context, body PostV1RegistryCredentialsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1RegistryCredentialsResponse, error) - - // DeleteV1RegistryCredentialsIdWithResponse request - DeleteV1RegistryCredentialsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1RegistryCredentialsIdResponse, error) - - // GetV1TemplatesWithResponse request - GetV1TemplatesWithResponse(ctx context.Context, params *GetV1TemplatesParams, reqEditors ...RequestEditorFn) (*GetV1TemplatesResponse, error) - - // PostV1TemplatesWithBodyWithResponse request with any body - PostV1TemplatesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1TemplatesResponse, error) - - PostV1TemplatesWithResponse(ctx context.Context, body PostV1TemplatesJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1TemplatesResponse, error) - - // DeleteV1TemplatesIdWithResponse request - DeleteV1TemplatesIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1TemplatesIdResponse, error) - - // GetV1TemplatesIdWithResponse request - GetV1TemplatesIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1TemplatesIdResponse, error) - - // PatchV1TemplatesIdWithBodyWithResponse request with any body - PatchV1TemplatesIdWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1TemplatesIdResponse, error) - - PatchV1TemplatesIdWithResponse(ctx context.Context, id string, body PatchV1TemplatesIdJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1TemplatesIdResponse, error) - - // GetV1UserTokensWithResponse request - GetV1UserTokensWithResponse(ctx context.Context, params *GetV1UserTokensParams, reqEditors ...RequestEditorFn) (*GetV1UserTokensResponse, error) - - // PostV1UserTokensWithBodyWithResponse request with any body - PostV1UserTokensWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1UserTokensResponse, error) - - PostV1UserTokensWithResponse(ctx context.Context, body PostV1UserTokensJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1UserTokensResponse, error) - - // DeleteV1UserTokensIdWithResponse request - DeleteV1UserTokensIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1UserTokensIdResponse, error) - - // GetV1WorkspacesWithResponse request - GetV1WorkspacesWithResponse(ctx context.Context, params *GetV1WorkspacesParams, reqEditors ...RequestEditorFn) (*GetV1WorkspacesResponse, error) - - // GetV1WorkspacesIdWithResponse request - GetV1WorkspacesIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1WorkspacesIdResponse, error) -} - -type GetV1ClustersResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *ClusterList - JSON401 *Error - JSON403 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1ClustersResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1ClustersResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type DeleteV1ClustersIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON403 *Error - JSON404 *Error - JSON409 *Error -} - -// Status returns HTTPResponse.Status -func (r DeleteV1ClustersIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteV1ClustersIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1ClustersIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *Cluster - JSON401 *Error - JSON403 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1ClustersIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1ClustersIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PatchV1ClustersIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *Cluster - JSON401 *Error - JSON403 *Error - JSON404 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PatchV1ClustersIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PatchV1ClustersIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1ClustersIdKubeconfigResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *map[string]*interface{} - YAML200 *string - JSON400 *Error - JSON401 *Error - JSON403 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1ClustersIdKubeconfigResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1ClustersIdKubeconfigResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1InstallsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *InstallList - JSON401 *Error - JSON403 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1InstallsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1InstallsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1InstallsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON403 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1InstallsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1InstallsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1InstallsStandaloneResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON403 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1InstallsStandaloneResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1InstallsStandaloneResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type DeleteV1InstallsIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r DeleteV1InstallsIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteV1InstallsIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1InstallsIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *Install - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1InstallsIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1InstallsIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1InstallsIdLogsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1InstallsIdLogsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1InstallsIdLogsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PatchV1InstallsIdOverridesResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PatchV1InstallsIdOverridesResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PatchV1InstallsIdOverridesResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1InstallsIdPodsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - Data []Pod `json:"data"` - } - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1InstallsIdPodsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1InstallsIdPodsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PatchV1InstallsIdValuesResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PatchV1InstallsIdValuesResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PatchV1InstallsIdValuesResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1ProductsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *ProductList - JSON401 *Error - JSON403 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1ProductsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1ProductsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1ProductsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON201 *struct { - ProductId string `json:"product_id"` - TemplateId string `json:"template_id"` - } - JSON401 *Error - JSON403 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1ProductsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1ProductsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type DeleteV1ProductsIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error - JSON409 *Error -} - -// Status returns HTTPResponse.Status -func (r DeleteV1ProductsIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteV1ProductsIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1ProductsIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *Product - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1ProductsIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1ProductsIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PatchV1ProductsIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - ProductId string `json:"product_id"` - TemplateId string `json:"template_id"` - } - JSON401 *Error - JSON404 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PatchV1ProductsIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PatchV1ProductsIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1RegionsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *RegionList - JSON401 *Error - JSON403 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1RegionsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1RegionsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1RegionsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON201 *Region - JSON401 *Error - JSON403 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1RegionsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1RegionsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1RegistryCredentialsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *RegistryCredentialList - JSON401 *Error - JSON403 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1RegistryCredentialsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1RegistryCredentialsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1RegistryCredentialsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON403 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1RegistryCredentialsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1RegistryCredentialsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type DeleteV1RegistryCredentialsIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r DeleteV1RegistryCredentialsIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteV1RegistryCredentialsIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1TemplatesResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *TemplateList - JSON401 *Error - JSON403 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1TemplatesResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1TemplatesResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1TemplatesResponse struct { - Body []byte - HTTPResponse *http.Response - JSON201 *struct { - TemplateId string `json:"template_id"` - } - JSON401 *Error - JSON403 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1TemplatesResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1TemplatesResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type DeleteV1TemplatesIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error - JSON409 *Error -} - -// Status returns HTTPResponse.Status -func (r DeleteV1TemplatesIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteV1TemplatesIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1TemplatesIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *TemplateDetail - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1TemplatesIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1TemplatesIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PatchV1TemplatesIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - TemplateId string `json:"template_id"` - } - JSON401 *Error - JSON404 *Error - JSON422 *Error -} - -// Status returns HTTPResponse.Status -func (r PatchV1TemplatesIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PatchV1TemplatesIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1UserTokensResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *ApiTokenList - JSON401 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1UserTokensResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1UserTokensResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PostV1UserTokensResponse struct { - Body []byte - HTTPResponse *http.Response - JSON201 *CreatedToken - JSON401 *Error -} - -// Status returns HTTPResponse.Status -func (r PostV1UserTokensResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PostV1UserTokensResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type DeleteV1UserTokensIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON401 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r DeleteV1UserTokensIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteV1UserTokensIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1WorkspacesResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *WorkspaceList - JSON401 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1WorkspacesResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1WorkspacesResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetV1WorkspacesIdResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *Workspace - JSON401 *Error - JSON403 *Error - JSON404 *Error -} - -// Status returns HTTPResponse.Status -func (r GetV1WorkspacesIdResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV1WorkspacesIdResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// GetV1ClustersWithResponse request returning *GetV1ClustersResponse -func (c *ClientWithResponses) GetV1ClustersWithResponse(ctx context.Context, params *GetV1ClustersParams, reqEditors ...RequestEditorFn) (*GetV1ClustersResponse, error) { - rsp, err := c.GetV1Clusters(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1ClustersResponse(rsp) -} - -// DeleteV1ClustersIdWithResponse request returning *DeleteV1ClustersIdResponse -func (c *ClientWithResponses) DeleteV1ClustersIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1ClustersIdResponse, error) { - rsp, err := c.DeleteV1ClustersId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteV1ClustersIdResponse(rsp) -} - -// GetV1ClustersIdWithResponse request returning *GetV1ClustersIdResponse -func (c *ClientWithResponses) GetV1ClustersIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1ClustersIdResponse, error) { - rsp, err := c.GetV1ClustersId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1ClustersIdResponse(rsp) -} - -// PatchV1ClustersIdWithBodyWithResponse request with arbitrary body returning *PatchV1ClustersIdResponse -func (c *ClientWithResponses) PatchV1ClustersIdWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1ClustersIdResponse, error) { - rsp, err := c.PatchV1ClustersIdWithBody(ctx, id, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1ClustersIdResponse(rsp) -} - -func (c *ClientWithResponses) PatchV1ClustersIdWithResponse(ctx context.Context, id string, body PatchV1ClustersIdJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1ClustersIdResponse, error) { - rsp, err := c.PatchV1ClustersId(ctx, id, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1ClustersIdResponse(rsp) -} - -// GetV1ClustersIdKubeconfigWithResponse request returning *GetV1ClustersIdKubeconfigResponse -func (c *ClientWithResponses) GetV1ClustersIdKubeconfigWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1ClustersIdKubeconfigResponse, error) { - rsp, err := c.GetV1ClustersIdKubeconfig(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1ClustersIdKubeconfigResponse(rsp) -} - -// GetV1InstallsWithResponse request returning *GetV1InstallsResponse -func (c *ClientWithResponses) GetV1InstallsWithResponse(ctx context.Context, params *GetV1InstallsParams, reqEditors ...RequestEditorFn) (*GetV1InstallsResponse, error) { - rsp, err := c.GetV1Installs(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1InstallsResponse(rsp) -} - -// PostV1InstallsWithBodyWithResponse request with arbitrary body returning *PostV1InstallsResponse -func (c *ClientWithResponses) PostV1InstallsWithBodyWithResponse(ctx context.Context, params *PostV1InstallsParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1InstallsResponse, error) { - rsp, err := c.PostV1InstallsWithBody(ctx, params, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1InstallsResponse(rsp) -} - -func (c *ClientWithResponses) PostV1InstallsWithResponse(ctx context.Context, params *PostV1InstallsParams, body PostV1InstallsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1InstallsResponse, error) { - rsp, err := c.PostV1Installs(ctx, params, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1InstallsResponse(rsp) -} - -// PostV1InstallsStandaloneWithBodyWithResponse request with arbitrary body returning *PostV1InstallsStandaloneResponse -func (c *ClientWithResponses) PostV1InstallsStandaloneWithBodyWithResponse(ctx context.Context, params *PostV1InstallsStandaloneParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1InstallsStandaloneResponse, error) { - rsp, err := c.PostV1InstallsStandaloneWithBody(ctx, params, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1InstallsStandaloneResponse(rsp) -} - -func (c *ClientWithResponses) PostV1InstallsStandaloneWithResponse(ctx context.Context, params *PostV1InstallsStandaloneParams, body PostV1InstallsStandaloneJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1InstallsStandaloneResponse, error) { - rsp, err := c.PostV1InstallsStandalone(ctx, params, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1InstallsStandaloneResponse(rsp) -} - -// DeleteV1InstallsIdWithResponse request returning *DeleteV1InstallsIdResponse -func (c *ClientWithResponses) DeleteV1InstallsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1InstallsIdResponse, error) { - rsp, err := c.DeleteV1InstallsId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteV1InstallsIdResponse(rsp) -} - -// GetV1InstallsIdWithResponse request returning *GetV1InstallsIdResponse -func (c *ClientWithResponses) GetV1InstallsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1InstallsIdResponse, error) { - rsp, err := c.GetV1InstallsId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1InstallsIdResponse(rsp) -} - -// GetV1InstallsIdLogsWithResponse request returning *GetV1InstallsIdLogsResponse -func (c *ClientWithResponses) GetV1InstallsIdLogsWithResponse(ctx context.Context, id string, params *GetV1InstallsIdLogsParams, reqEditors ...RequestEditorFn) (*GetV1InstallsIdLogsResponse, error) { - rsp, err := c.GetV1InstallsIdLogs(ctx, id, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1InstallsIdLogsResponse(rsp) -} - -// PatchV1InstallsIdOverridesWithBodyWithResponse request with arbitrary body returning *PatchV1InstallsIdOverridesResponse -func (c *ClientWithResponses) PatchV1InstallsIdOverridesWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdOverridesResponse, error) { - rsp, err := c.PatchV1InstallsIdOverridesWithBody(ctx, id, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1InstallsIdOverridesResponse(rsp) -} - -func (c *ClientWithResponses) PatchV1InstallsIdOverridesWithResponse(ctx context.Context, id string, body PatchV1InstallsIdOverridesJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdOverridesResponse, error) { - rsp, err := c.PatchV1InstallsIdOverrides(ctx, id, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1InstallsIdOverridesResponse(rsp) -} - -// GetV1InstallsIdPodsWithResponse request returning *GetV1InstallsIdPodsResponse -func (c *ClientWithResponses) GetV1InstallsIdPodsWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1InstallsIdPodsResponse, error) { - rsp, err := c.GetV1InstallsIdPods(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1InstallsIdPodsResponse(rsp) -} - -// PatchV1InstallsIdValuesWithBodyWithResponse request with arbitrary body returning *PatchV1InstallsIdValuesResponse -func (c *ClientWithResponses) PatchV1InstallsIdValuesWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdValuesResponse, error) { - rsp, err := c.PatchV1InstallsIdValuesWithBody(ctx, id, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1InstallsIdValuesResponse(rsp) -} - -func (c *ClientWithResponses) PatchV1InstallsIdValuesWithResponse(ctx context.Context, id string, body PatchV1InstallsIdValuesJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1InstallsIdValuesResponse, error) { - rsp, err := c.PatchV1InstallsIdValues(ctx, id, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1InstallsIdValuesResponse(rsp) -} - -// GetV1ProductsWithResponse request returning *GetV1ProductsResponse -func (c *ClientWithResponses) GetV1ProductsWithResponse(ctx context.Context, params *GetV1ProductsParams, reqEditors ...RequestEditorFn) (*GetV1ProductsResponse, error) { - rsp, err := c.GetV1Products(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1ProductsResponse(rsp) -} - -// PostV1ProductsWithBodyWithResponse request with arbitrary body returning *PostV1ProductsResponse -func (c *ClientWithResponses) PostV1ProductsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1ProductsResponse, error) { - rsp, err := c.PostV1ProductsWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1ProductsResponse(rsp) -} - -func (c *ClientWithResponses) PostV1ProductsWithResponse(ctx context.Context, body PostV1ProductsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1ProductsResponse, error) { - rsp, err := c.PostV1Products(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1ProductsResponse(rsp) -} - -// DeleteV1ProductsIdWithResponse request returning *DeleteV1ProductsIdResponse -func (c *ClientWithResponses) DeleteV1ProductsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1ProductsIdResponse, error) { - rsp, err := c.DeleteV1ProductsId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteV1ProductsIdResponse(rsp) -} - -// GetV1ProductsIdWithResponse request returning *GetV1ProductsIdResponse -func (c *ClientWithResponses) GetV1ProductsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1ProductsIdResponse, error) { - rsp, err := c.GetV1ProductsId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1ProductsIdResponse(rsp) -} - -// PatchV1ProductsIdWithBodyWithResponse request with arbitrary body returning *PatchV1ProductsIdResponse -func (c *ClientWithResponses) PatchV1ProductsIdWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1ProductsIdResponse, error) { - rsp, err := c.PatchV1ProductsIdWithBody(ctx, id, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1ProductsIdResponse(rsp) -} - -func (c *ClientWithResponses) PatchV1ProductsIdWithResponse(ctx context.Context, id string, body PatchV1ProductsIdJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1ProductsIdResponse, error) { - rsp, err := c.PatchV1ProductsId(ctx, id, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1ProductsIdResponse(rsp) -} - -// GetV1RegionsWithResponse request returning *GetV1RegionsResponse -func (c *ClientWithResponses) GetV1RegionsWithResponse(ctx context.Context, params *GetV1RegionsParams, reqEditors ...RequestEditorFn) (*GetV1RegionsResponse, error) { - rsp, err := c.GetV1Regions(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1RegionsResponse(rsp) -} - -// PostV1RegionsWithBodyWithResponse request with arbitrary body returning *PostV1RegionsResponse -func (c *ClientWithResponses) PostV1RegionsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1RegionsResponse, error) { - rsp, err := c.PostV1RegionsWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1RegionsResponse(rsp) -} - -func (c *ClientWithResponses) PostV1RegionsWithResponse(ctx context.Context, body PostV1RegionsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1RegionsResponse, error) { - rsp, err := c.PostV1Regions(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1RegionsResponse(rsp) -} - -// GetV1RegistryCredentialsWithResponse request returning *GetV1RegistryCredentialsResponse -func (c *ClientWithResponses) GetV1RegistryCredentialsWithResponse(ctx context.Context, params *GetV1RegistryCredentialsParams, reqEditors ...RequestEditorFn) (*GetV1RegistryCredentialsResponse, error) { - rsp, err := c.GetV1RegistryCredentials(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1RegistryCredentialsResponse(rsp) -} - -// PostV1RegistryCredentialsWithBodyWithResponse request with arbitrary body returning *PostV1RegistryCredentialsResponse -func (c *ClientWithResponses) PostV1RegistryCredentialsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1RegistryCredentialsResponse, error) { - rsp, err := c.PostV1RegistryCredentialsWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1RegistryCredentialsResponse(rsp) -} - -func (c *ClientWithResponses) PostV1RegistryCredentialsWithResponse(ctx context.Context, body PostV1RegistryCredentialsJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1RegistryCredentialsResponse, error) { - rsp, err := c.PostV1RegistryCredentials(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1RegistryCredentialsResponse(rsp) -} - -// DeleteV1RegistryCredentialsIdWithResponse request returning *DeleteV1RegistryCredentialsIdResponse -func (c *ClientWithResponses) DeleteV1RegistryCredentialsIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1RegistryCredentialsIdResponse, error) { - rsp, err := c.DeleteV1RegistryCredentialsId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteV1RegistryCredentialsIdResponse(rsp) -} - -// GetV1TemplatesWithResponse request returning *GetV1TemplatesResponse -func (c *ClientWithResponses) GetV1TemplatesWithResponse(ctx context.Context, params *GetV1TemplatesParams, reqEditors ...RequestEditorFn) (*GetV1TemplatesResponse, error) { - rsp, err := c.GetV1Templates(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1TemplatesResponse(rsp) -} - -// PostV1TemplatesWithBodyWithResponse request with arbitrary body returning *PostV1TemplatesResponse -func (c *ClientWithResponses) PostV1TemplatesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1TemplatesResponse, error) { - rsp, err := c.PostV1TemplatesWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1TemplatesResponse(rsp) -} - -func (c *ClientWithResponses) PostV1TemplatesWithResponse(ctx context.Context, body PostV1TemplatesJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1TemplatesResponse, error) { - rsp, err := c.PostV1Templates(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1TemplatesResponse(rsp) -} - -// DeleteV1TemplatesIdWithResponse request returning *DeleteV1TemplatesIdResponse -func (c *ClientWithResponses) DeleteV1TemplatesIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1TemplatesIdResponse, error) { - rsp, err := c.DeleteV1TemplatesId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteV1TemplatesIdResponse(rsp) -} - -// GetV1TemplatesIdWithResponse request returning *GetV1TemplatesIdResponse -func (c *ClientWithResponses) GetV1TemplatesIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1TemplatesIdResponse, error) { - rsp, err := c.GetV1TemplatesId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1TemplatesIdResponse(rsp) -} - -// PatchV1TemplatesIdWithBodyWithResponse request with arbitrary body returning *PatchV1TemplatesIdResponse -func (c *ClientWithResponses) PatchV1TemplatesIdWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchV1TemplatesIdResponse, error) { - rsp, err := c.PatchV1TemplatesIdWithBody(ctx, id, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1TemplatesIdResponse(rsp) -} - -func (c *ClientWithResponses) PatchV1TemplatesIdWithResponse(ctx context.Context, id string, body PatchV1TemplatesIdJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchV1TemplatesIdResponse, error) { - rsp, err := c.PatchV1TemplatesId(ctx, id, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchV1TemplatesIdResponse(rsp) -} - -// GetV1UserTokensWithResponse request returning *GetV1UserTokensResponse -func (c *ClientWithResponses) GetV1UserTokensWithResponse(ctx context.Context, params *GetV1UserTokensParams, reqEditors ...RequestEditorFn) (*GetV1UserTokensResponse, error) { - rsp, err := c.GetV1UserTokens(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1UserTokensResponse(rsp) -} - -// PostV1UserTokensWithBodyWithResponse request with arbitrary body returning *PostV1UserTokensResponse -func (c *ClientWithResponses) PostV1UserTokensWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostV1UserTokensResponse, error) { - rsp, err := c.PostV1UserTokensWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1UserTokensResponse(rsp) -} - -func (c *ClientWithResponses) PostV1UserTokensWithResponse(ctx context.Context, body PostV1UserTokensJSONRequestBody, reqEditors ...RequestEditorFn) (*PostV1UserTokensResponse, error) { - rsp, err := c.PostV1UserTokens(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePostV1UserTokensResponse(rsp) -} - -// DeleteV1UserTokensIdWithResponse request returning *DeleteV1UserTokensIdResponse -func (c *ClientWithResponses) DeleteV1UserTokensIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeleteV1UserTokensIdResponse, error) { - rsp, err := c.DeleteV1UserTokensId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteV1UserTokensIdResponse(rsp) -} - -// GetV1WorkspacesWithResponse request returning *GetV1WorkspacesResponse -func (c *ClientWithResponses) GetV1WorkspacesWithResponse(ctx context.Context, params *GetV1WorkspacesParams, reqEditors ...RequestEditorFn) (*GetV1WorkspacesResponse, error) { - rsp, err := c.GetV1Workspaces(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1WorkspacesResponse(rsp) -} - -// GetV1WorkspacesIdWithResponse request returning *GetV1WorkspacesIdResponse -func (c *ClientWithResponses) GetV1WorkspacesIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetV1WorkspacesIdResponse, error) { - rsp, err := c.GetV1WorkspacesId(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV1WorkspacesIdResponse(rsp) -} - -// ParseGetV1ClustersResponse parses an HTTP response from a GetV1ClustersWithResponse call -func ParseGetV1ClustersResponse(rsp *http.Response) (*GetV1ClustersResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1ClustersResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest ClusterList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - } - - return response, nil -} - -// ParseDeleteV1ClustersIdResponse parses an HTTP response from a DeleteV1ClustersIdWithResponse call -func ParseDeleteV1ClustersIdResponse(rsp *http.Response) (*DeleteV1ClustersIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteV1ClustersIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON409 = &dest - - } - - return response, nil -} - -// ParseGetV1ClustersIdResponse parses an HTTP response from a GetV1ClustersIdWithResponse call -func ParseGetV1ClustersIdResponse(rsp *http.Response) (*GetV1ClustersIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1ClustersIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Cluster - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParsePatchV1ClustersIdResponse parses an HTTP response from a PatchV1ClustersIdWithResponse call -func ParsePatchV1ClustersIdResponse(rsp *http.Response) (*PatchV1ClustersIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchV1ClustersIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Cluster - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseGetV1ClustersIdKubeconfigResponse parses an HTTP response from a GetV1ClustersIdKubeconfigWithResponse call -func ParseGetV1ClustersIdKubeconfigResponse(rsp *http.Response) (*GetV1ClustersIdKubeconfigResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1ClustersIdKubeconfigResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest map[string]*interface{} - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "yaml") && rsp.StatusCode == 200: - var dest string - if err := yaml.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.YAML200 = &dest - - } - - return response, nil -} - -// ParseGetV1InstallsResponse parses an HTTP response from a GetV1InstallsWithResponse call -func ParseGetV1InstallsResponse(rsp *http.Response) (*GetV1InstallsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1InstallsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest InstallList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - } - - return response, nil -} - -// ParsePostV1InstallsResponse parses an HTTP response from a PostV1InstallsWithResponse call -func ParsePostV1InstallsResponse(rsp *http.Response) (*PostV1InstallsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1InstallsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParsePostV1InstallsStandaloneResponse parses an HTTP response from a PostV1InstallsStandaloneWithResponse call -func ParsePostV1InstallsStandaloneResponse(rsp *http.Response) (*PostV1InstallsStandaloneResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1InstallsStandaloneResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseDeleteV1InstallsIdResponse parses an HTTP response from a DeleteV1InstallsIdWithResponse call -func ParseDeleteV1InstallsIdResponse(rsp *http.Response) (*DeleteV1InstallsIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteV1InstallsIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParseGetV1InstallsIdResponse parses an HTTP response from a GetV1InstallsIdWithResponse call -func ParseGetV1InstallsIdResponse(rsp *http.Response) (*GetV1InstallsIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1InstallsIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Install - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParseGetV1InstallsIdLogsResponse parses an HTTP response from a GetV1InstallsIdLogsWithResponse call -func ParseGetV1InstallsIdLogsResponse(rsp *http.Response) (*GetV1InstallsIdLogsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1InstallsIdLogsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParsePatchV1InstallsIdOverridesResponse parses an HTTP response from a PatchV1InstallsIdOverridesWithResponse call -func ParsePatchV1InstallsIdOverridesResponse(rsp *http.Response) (*PatchV1InstallsIdOverridesResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchV1InstallsIdOverridesResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseGetV1InstallsIdPodsResponse parses an HTTP response from a GetV1InstallsIdPodsWithResponse call -func ParseGetV1InstallsIdPodsResponse(rsp *http.Response) (*GetV1InstallsIdPodsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1InstallsIdPodsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - Data []Pod `json:"data"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParsePatchV1InstallsIdValuesResponse parses an HTTP response from a PatchV1InstallsIdValuesWithResponse call -func ParsePatchV1InstallsIdValuesResponse(rsp *http.Response) (*PatchV1InstallsIdValuesResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchV1InstallsIdValuesResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseGetV1ProductsResponse parses an HTTP response from a GetV1ProductsWithResponse call -func ParseGetV1ProductsResponse(rsp *http.Response) (*GetV1ProductsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1ProductsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest ProductList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - } - - return response, nil -} - -// ParsePostV1ProductsResponse parses an HTTP response from a PostV1ProductsWithResponse call -func ParsePostV1ProductsResponse(rsp *http.Response) (*PostV1ProductsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1ProductsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201: - var dest struct { - ProductId string `json:"product_id"` - TemplateId string `json:"template_id"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON201 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseDeleteV1ProductsIdResponse parses an HTTP response from a DeleteV1ProductsIdWithResponse call -func ParseDeleteV1ProductsIdResponse(rsp *http.Response) (*DeleteV1ProductsIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteV1ProductsIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON409 = &dest - - } - - return response, nil -} - -// ParseGetV1ProductsIdResponse parses an HTTP response from a GetV1ProductsIdWithResponse call -func ParseGetV1ProductsIdResponse(rsp *http.Response) (*GetV1ProductsIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1ProductsIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Product - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParsePatchV1ProductsIdResponse parses an HTTP response from a PatchV1ProductsIdWithResponse call -func ParsePatchV1ProductsIdResponse(rsp *http.Response) (*PatchV1ProductsIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchV1ProductsIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - ProductId string `json:"product_id"` - TemplateId string `json:"template_id"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseGetV1RegionsResponse parses an HTTP response from a GetV1RegionsWithResponse call -func ParseGetV1RegionsResponse(rsp *http.Response) (*GetV1RegionsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1RegionsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest RegionList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - } - - return response, nil -} - -// ParsePostV1RegionsResponse parses an HTTP response from a PostV1RegionsWithResponse call -func ParsePostV1RegionsResponse(rsp *http.Response) (*PostV1RegionsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1RegionsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201: - var dest Region - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON201 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseGetV1RegistryCredentialsResponse parses an HTTP response from a GetV1RegistryCredentialsWithResponse call -func ParseGetV1RegistryCredentialsResponse(rsp *http.Response) (*GetV1RegistryCredentialsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1RegistryCredentialsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest RegistryCredentialList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - } - - return response, nil -} - -// ParsePostV1RegistryCredentialsResponse parses an HTTP response from a PostV1RegistryCredentialsWithResponse call -func ParsePostV1RegistryCredentialsResponse(rsp *http.Response) (*PostV1RegistryCredentialsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1RegistryCredentialsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseDeleteV1RegistryCredentialsIdResponse parses an HTTP response from a DeleteV1RegistryCredentialsIdWithResponse call -func ParseDeleteV1RegistryCredentialsIdResponse(rsp *http.Response) (*DeleteV1RegistryCredentialsIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteV1RegistryCredentialsIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParseGetV1TemplatesResponse parses an HTTP response from a GetV1TemplatesWithResponse call -func ParseGetV1TemplatesResponse(rsp *http.Response) (*GetV1TemplatesResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1TemplatesResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest TemplateList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - } - - return response, nil -} - -// ParsePostV1TemplatesResponse parses an HTTP response from a PostV1TemplatesWithResponse call -func ParsePostV1TemplatesResponse(rsp *http.Response) (*PostV1TemplatesResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1TemplatesResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201: - var dest struct { - TemplateId string `json:"template_id"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON201 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseDeleteV1TemplatesIdResponse parses an HTTP response from a DeleteV1TemplatesIdWithResponse call -func ParseDeleteV1TemplatesIdResponse(rsp *http.Response) (*DeleteV1TemplatesIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteV1TemplatesIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON409 = &dest - - } - - return response, nil -} - -// ParseGetV1TemplatesIdResponse parses an HTTP response from a GetV1TemplatesIdWithResponse call -func ParseGetV1TemplatesIdResponse(rsp *http.Response) (*GetV1TemplatesIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1TemplatesIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest TemplateDetail - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParsePatchV1TemplatesIdResponse parses an HTTP response from a PatchV1TemplatesIdWithResponse call -func ParsePatchV1TemplatesIdResponse(rsp *http.Response) (*PatchV1TemplatesIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchV1TemplatesIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - TemplateId string `json:"template_id"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 422: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON422 = &dest - - } - - return response, nil -} - -// ParseGetV1UserTokensResponse parses an HTTP response from a GetV1UserTokensWithResponse call -func ParseGetV1UserTokensResponse(rsp *http.Response) (*GetV1UserTokensResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1UserTokensResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest ApiTokenList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - } - - return response, nil -} - -// ParsePostV1UserTokensResponse parses an HTTP response from a PostV1UserTokensWithResponse call -func ParsePostV1UserTokensResponse(rsp *http.Response) (*PostV1UserTokensResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PostV1UserTokensResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201: - var dest CreatedToken - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON201 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - } - - return response, nil -} - -// ParseDeleteV1UserTokensIdResponse parses an HTTP response from a DeleteV1UserTokensIdWithResponse call -func ParseDeleteV1UserTokensIdResponse(rsp *http.Response) (*DeleteV1UserTokensIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteV1UserTokensIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} - -// ParseGetV1WorkspacesResponse parses an HTTP response from a GetV1WorkspacesWithResponse call -func ParseGetV1WorkspacesResponse(rsp *http.Response) (*GetV1WorkspacesResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1WorkspacesResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest WorkspaceList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - } - - return response, nil -} - -// ParseGetV1WorkspacesIdResponse parses an HTTP response from a GetV1WorkspacesIdWithResponse call -func ParseGetV1WorkspacesIdResponse(rsp *http.Response) (*GetV1WorkspacesIdResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV1WorkspacesIdResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest Workspace - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest Error - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - } - - return response, nil -} diff --git a/internal/api/oapi-codegen.yaml b/internal/api/oapi-codegen.yaml deleted file mode 100644 index 81aeb5f..0000000 --- a/internal/api/oapi-codegen.yaml +++ /dev/null @@ -1,7 +0,0 @@ -package: api -output: internal/api/client.gen.go -generate: - models: true - client: true -output-options: - client-type-name: Client diff --git a/internal/api/openapi.json b/internal/api/openapi.json deleted file mode 100644 index 2102075..0000000 --- a/internal/api/openapi.json +++ /dev/null @@ -1 +0,0 @@ -{"openapi":"3.1.0","info":{"title":"CNAP API","version":"1.0.0","description":"Public API for managing CNAP workspaces, clusters, templates, products, and deployments.\n\nAuthenticate with a Personal Access Token via the `Authorization: Bearer cnap_pat_...` header.\n\nWorkspace-scoped endpoints require the `X-Workspace-Id` header."},"servers":[{"url":"https://api.cnap.tech","description":"Production"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"Personal Access Token (cnap_pat_...) or OAuth2 JWT. Create tokens at https://cnap.tech/settings/tokens"}},"schemas":{"ApiTokenList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiToken"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"ApiToken":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"My CLI token"},"prefix":{"type":"string","example":"cnap_pat_a3b2"},"created_at":{"type":"number","description":"Unix timestamp (seconds)","example":1708000000},"last_used_at":{"type":"number","nullable":true,"description":"Unix timestamp (seconds) of last use"},"expires_at":{"type":"number","nullable":true,"description":"Unix timestamp (seconds), null if never"}},"required":["id","name","prefix","created_at","last_used_at","expires_at"]},"Pagination":{"type":"object","properties":{"cursor":{"type":"string","nullable":true,"description":"Cursor for next page, null if no more"},"has_more":{"type":"boolean"}},"required":["cursor","has_more"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"not_found"},"message":{"type":"string","example":"Resource not found"},"param":{"type":"string","description":"The request field that caused the error","example":"name"},"suggestion":{"type":"string","example":"Run `cnap clusters list` to see available clusters"},"details":{"nullable":true}},"required":["code","message"]}},"required":["error"]},"CreatedToken":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"token":{"type":"string","description":"The full token. This is shown only once — store it securely.","example":"cnap_pat_a3b2c4d5e6f7g8h9i0j1k2l3m4n5o6p7"}},"required":["id","name","token"]},"WorkspaceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Workspace"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Workspace":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"My Workspace"},"icon":{"type":"string","nullable":true,"example":null},"created_at":{"type":"number","description":"Unix timestamp (seconds)"}},"required":["id","name","icon","created_at"]},"ClusterList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Cluster"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Cluster":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"production"},"workspace_id":{"type":"string","example":"j572abc123def456"},"region_id":{"type":"string","example":"j572abc123def456"},"kaas":{"$ref":"#/components/schemas/KaasInfo"},"created_at":{"type":"number","description":"Unix timestamp (seconds)"}},"required":["id","name","workspace_id","region_id","kaas","created_at"]},"KaasInfo":{"type":"object","nullable":true,"properties":{"version":{"type":"string","example":"v1.30"},"status":{"type":"string","enum":["PROVISIONING","RUNNING","RECONCILING","DELETING","ERROR","DEGRADED"],"example":"RUNNING"},"status_message":{"type":"string","nullable":true,"example":null}},"required":["version","status","status_message"],"description":"Present if cluster is KaaS-managed"},"TemplateList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Template"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Template":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"PostgreSQL HA"},"workspace_id":{"type":"string","example":"j572abc123def456"},"registry_proxy_mode":{"type":"string","nullable":true,"enum":["auto","always","never",null],"example":"auto"},"created_at":{"type":"number","description":"Unix timestamp (seconds)"}},"required":["id","name","workspace_id","registry_proxy_mode","created_at"]},"TemplateDetail":{"allOf":[{"$ref":"#/components/schemas/Template"},{"type":"object","properties":{"helm_sources":{"type":"array","items":{"$ref":"#/components/schemas/HelmSource"}}},"required":["helm_sources"]}]},"HelmSource":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"chart":{"$ref":"#/components/schemas/HelmSourceChart"},"values":{"type":"object","additionalProperties":{"nullable":true}},"metadata":{"type":"object","additionalProperties":{"nullable":true}}},"required":["id","chart"]},"HelmSourceChart":{"type":"object","properties":{"repo_url":{"type":"string","example":"https://charts.bitnami.com/bitnami"},"chart":{"type":"string","example":"postgresql"},"target_revision":{"type":"string","example":"15.5.0"},"path":{"type":"string","example":"charts/my-chart"}},"required":["repo_url","target_revision"]},"ProductList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Product":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"PostgreSQL Managed"},"workspace_id":{"type":"string","example":"j572abc123def456"},"template_id":{"type":"string","example":"j572abc123def456"},"settings":{"type":"object","nullable":true,"properties":{"custom_image":{"type":"string"},"custom_description":{"type":"string"},"show_sources":{"type":"boolean"}}},"created_at":{"type":"number","description":"Unix timestamp (seconds)"}},"required":["id","name","workspace_id","template_id","settings","created_at"]},"InstallList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Install"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Install":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","nullable":true,"example":"my-postgres"},"workspace_id":{"type":"string","example":"j572abc123def456"},"product_id":{"type":"string","nullable":true,"description":"Set for product-based installs"},"template_id":{"type":"string","nullable":true,"description":"Template driving this install"},"cluster_id":{"type":"string","example":"j572abc123def456"},"created_at":{"type":"number","description":"Unix timestamp (seconds)"}},"required":["id","name","workspace_id","product_id","template_id","cluster_id","created_at"]},"Pod":{"type":"object","properties":{"name":{"type":"string","example":"postgres-0"},"containers":{"type":"array","items":{"type":"string"},"example":["postgresql"]}},"required":["name","containers"]},"RegionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Region"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Region":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"us-east-1"},"icon":{"type":"string","nullable":true,"description":"Icon URL"},"workspace_id":{"type":"string","example":"j572abc123def456"},"created_at":{"type":"number","description":"Unix timestamp (seconds)"}},"required":["id","name","icon","workspace_id","created_at"]},"RegistryCredentialList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RegistryCredential"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"RegistryCredential":{"type":"object","properties":{"id":{"type":"string","example":"j572abc123def456"},"name":{"type":"string","example":"GitHub Container Registry"},"registry_url":{"type":"string","example":"ghcr.io"},"type":{"type":"string","enum":["basic","token","oauth"],"description":"Auth type"},"is_active":{"type":"boolean","description":"Whether the credential is active"},"created_at":{"type":"number","description":"Unix timestamp (seconds)"},"last_used_at":{"type":"number","nullable":true,"description":"Unix timestamp (seconds)"}},"required":["id","name","registry_url","type","is_active","created_at","last_used_at"]}},"parameters":{}},"paths":{"/v1/user/tokens":{"get":{"tags":["Auth"],"summary":"List personal access tokens","description":"Returns metadata for all tokens. Full token values are never shown after creation.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTokenList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Auth"],"summary":"Create a personal access token","description":"Creates a new PAT. The full token is returned in the response and never shown again.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Human-readable name for the token","example":"My CLI token"},"expires_at":{"type":"integer","minimum":0,"exclusiveMinimum":true,"description":"Unix timestamp (seconds) when the token expires. Omit for no expiry.","example":1742169600}},"required":["name"]}}}},"responses":{"201":{"description":"Token created. The `token` field is shown only once.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedToken"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/user/tokens/{id}":{"delete":{"tags":["Auth"],"summary":"Revoke a personal access token","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Token ID"},"required":true,"description":"Token ID","name":"id","in":"path"}],"responses":{"204":{"description":"Token revoked"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/workspaces":{"get":{"tags":["Workspaces"],"summary":"List workspaces","description":"Lists all workspaces the authenticated user belongs to. No X-Workspace-Id needed.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of workspaces","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/workspaces/{id}":{"get":{"tags":["Workspaces"],"summary":"Get workspace details","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Workspace ID"},"required":true,"description":"Workspace ID","name":"id","in":"path"}],"responses":{"200":{"description":"Workspace details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not a member of this workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Workspace not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/clusters":{"get":{"tags":["Clusters"],"summary":"List clusters in workspace","description":"Lists all clusters in the workspace specified by the X-Workspace-Id header.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of clusters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/clusters/{id}":{"get":{"tags":["Clusters"],"summary":"Get cluster details","description":"Returns detailed information about a cluster, including KaaS status if applicable.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Cluster ID"},"required":true,"description":"Cluster ID","name":"id","in":"path"}],"responses":{"200":{"description":"Cluster details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cluster"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not a member of the cluster workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cluster not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Clusters"],"summary":"Update cluster","description":"Update cluster name or region. The region must be in the same workspace.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Cluster ID"},"required":true,"description":"Cluster ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"staging"},"region_id":{"type":"string","description":"Region ID"}}}}}},"responses":{"200":{"description":"Updated cluster","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cluster"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not a member of the cluster workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cluster not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Clusters"],"summary":"Delete cluster","description":"Deletes a cluster and its configuration. KaaS-managed clusters are deprovisioned. Fails if the cluster has active installations.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Cluster ID"},"required":true,"description":"Cluster ID","name":"id","in":"path"}],"responses":{"204":{"description":"Cluster deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not a member of the cluster workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cluster not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Cluster has active installations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/clusters/{id}/kubeconfig":{"get":{"tags":["Clusters"],"summary":"Get cluster kubeconfig","description":"Returns the admin kubeconfig for a KaaS-managed cluster. The cluster must be in RUNNING status.\n\nSupports content negotiation via the `Accept` header:\n- `application/json` — returns JSON (default for API clients)\n- `application/yaml` — returns YAML (default for kubectl/CLI)","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Cluster ID"},"required":true,"description":"Cluster ID","name":"id","in":"path"}],"responses":{"200":{"description":"Admin kubeconfig","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true},"description":"Kubeconfig as JSON"}},"application/yaml":{"schema":{"type":"string"}}}},"400":{"description":"Cluster is not in RUNNING status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not a member of the cluster workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cluster not found or not KaaS-managed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/templates":{"get":{"tags":["Templates"],"summary":"List templates in workspace","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Templates"],"summary":"Create template","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"PostgreSQL HA"},"sources":{"type":"array","items":{"type":"object","properties":{"chart":{"type":"object","properties":{"repo_url":{"type":"string","minLength":1,"maxLength":2048},"chart":{"type":"string","minLength":1,"maxLength":100},"target_revision":{"type":"string","minLength":1,"maxLength":100},"path":{"type":"string","minLength":1,"maxLength":500}},"required":["repo_url","target_revision"]},"values":{"type":"object","additionalProperties":{"nullable":true}},"metadata":{"type":"object","properties":{"artifact_hub_helm_package":{"type":"object","additionalProperties":{"nullable":true}},"image":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2048},"tag":{"type":"string","minLength":1,"maxLength":200},"github":{"type":"object","properties":{"workflow_run_id":{"type":"string","minLength":1,"maxLength":100},"repository":{"type":"object","properties":{"id":{"type":"number"},"html_url":{"type":"string","minLength":1,"maxLength":2048},"name":{"type":"string","minLength":1,"maxLength":100},"full_name":{"type":"string","minLength":1,"maxLength":200},"owner":{"type":"object","properties":{"login":{"type":"string","minLength":1,"maxLength":100},"id":{"type":"number"},"type":{"type":"string","minLength":1,"maxLength":50},"avatar_url":{"type":"string","minLength":1,"maxLength":2048},"html_url":{"type":"string","minLength":1,"maxLength":2048}},"required":["login","id","type","avatar_url","html_url"]}},"required":["id","html_url","name","full_name","owner"]}}}},"required":["url","tag"]},"auto_deploy":{"type":"boolean"}}}},"required":["chart"]},"minItems":1},"registry_proxy_mode":{"type":"string","enum":["auto","always","never"]}},"required":["name","sources"]}}}},"responses":{"201":{"description":"Template created","content":{"application/json":{"schema":{"type":"object","properties":{"template_id":{"type":"string"}},"required":["template_id"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/templates/{id}":{"get":{"tags":["Templates"],"summary":"Get template details","description":"Returns template with its helm sources.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Template ID"},"required":true,"description":"Template ID","name":"id","in":"path"}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateDetail"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Template not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Templates"],"summary":"Update template","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Template ID"},"required":true,"description":"Template ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"sources":{"type":"array","items":{"type":"object","properties":{"chart":{"type":"object","properties":{"repo_url":{"type":"string","minLength":1,"maxLength":2048},"chart":{"type":"string","minLength":1,"maxLength":100},"target_revision":{"type":"string","minLength":1,"maxLength":100},"path":{"type":"string","minLength":1,"maxLength":500}},"required":["repo_url","target_revision"]},"values":{"type":"object","additionalProperties":{"nullable":true}},"metadata":{"type":"object","properties":{"artifact_hub_helm_package":{"type":"object","additionalProperties":{"nullable":true}},"image":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2048},"tag":{"type":"string","minLength":1,"maxLength":200},"github":{"type":"object","properties":{"workflow_run_id":{"type":"string","minLength":1,"maxLength":100},"repository":{"type":"object","properties":{"id":{"type":"number"},"html_url":{"type":"string","minLength":1,"maxLength":2048},"name":{"type":"string","minLength":1,"maxLength":100},"full_name":{"type":"string","minLength":1,"maxLength":200},"owner":{"type":"object","properties":{"login":{"type":"string","minLength":1,"maxLength":100},"id":{"type":"number"},"type":{"type":"string","minLength":1,"maxLength":50},"avatar_url":{"type":"string","minLength":1,"maxLength":2048},"html_url":{"type":"string","minLength":1,"maxLength":2048}},"required":["login","id","type","avatar_url","html_url"]}},"required":["id","html_url","name","full_name","owner"]}}}},"required":["url","tag"]},"auto_deploy":{"type":"boolean"}}}},"required":["chart"]},"minItems":1},"registry_proxy_mode":{"type":"string","enum":["auto","always","never"]}}}}}},"responses":{"200":{"description":"Template updated","content":{"application/json":{"schema":{"type":"object","properties":{"template_id":{"type":"string"}},"required":["template_id"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Template not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Templates"],"summary":"Delete template","description":"Fails if referenced by products or installs.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Template ID"},"required":true,"description":"Template ID","name":"id","in":"path"}],"responses":{"204":{"description":"Template deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Template not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Template is referenced by products or installs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/products":{"get":{"tags":["Products"],"summary":"List products in workspace","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of products","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Products"],"summary":"Create product","description":"Creates a product with helm sources and cluster associations. Triggers async chart generation.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":32,"example":"PostgreSQL Managed"},"sources":{"type":"array","items":{"type":"object","properties":{"chart":{"type":"object","properties":{"repo_url":{"type":"string","minLength":1,"maxLength":2048},"chart":{"type":"string","minLength":1,"maxLength":100},"target_revision":{"type":"string","minLength":1,"maxLength":100},"path":{"type":"string","minLength":1,"maxLength":500}},"required":["repo_url","target_revision"]},"values":{"type":"object","additionalProperties":{"nullable":true}},"metadata":{"type":"object","additionalProperties":{"nullable":true}}},"required":["chart"]},"minItems":1},"cluster_ids":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Cluster IDs to deploy to"},"stripe_price_ids":{"type":"array","items":{"type":"string"}},"settings":{"type":"object","properties":{"custom_image":{"type":"string","minLength":1,"maxLength":2048},"custom_description":{"type":"string","minLength":1,"maxLength":500},"show_sources":{"type":"boolean"}}}},"required":["name","sources","cluster_ids"]}}}},"responses":{"201":{"description":"Product created","content":{"application/json":{"schema":{"type":"object","properties":{"product_id":{"type":"string"},"template_id":{"type":"string"}},"required":["product_id","template_id"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/products/{id}":{"get":{"tags":["Products"],"summary":"Get product details","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Product ID"},"required":true,"description":"Product ID","name":"id","in":"path"}],"responses":{"200":{"description":"Product details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Products"],"summary":"Update product","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Product ID"},"required":true,"description":"Product ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":32,"example":"PostgreSQL Managed"},"sources":{"type":"array","items":{"type":"object","properties":{"chart":{"type":"object","properties":{"repo_url":{"type":"string","minLength":1,"maxLength":2048},"chart":{"type":"string","minLength":1,"maxLength":100},"target_revision":{"type":"string","minLength":1,"maxLength":100},"path":{"type":"string","minLength":1,"maxLength":500}},"required":["repo_url","target_revision"]},"values":{"type":"object","additionalProperties":{"nullable":true}},"metadata":{"type":"object","additionalProperties":{"nullable":true}}},"required":["chart"]},"minItems":1},"cluster_ids":{"type":"array","items":{"type":"string"},"minItems":1},"stripe_price_ids":{"type":"array","items":{"type":"string"}},"settings":{"type":"object","properties":{"custom_image":{"type":"string","minLength":1,"maxLength":2048},"custom_description":{"type":"string","minLength":1,"maxLength":500},"show_sources":{"type":"boolean"}}}},"required":["name","sources","cluster_ids"]}}}},"responses":{"200":{"description":"Product updated","content":{"application/json":{"schema":{"type":"object","properties":{"product_id":{"type":"string"},"template_id":{"type":"string"}},"required":["product_id","template_id"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Products"],"summary":"Delete product","description":"Fails if the product has active installs.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Product ID"},"required":true,"description":"Product ID","name":"id","in":"path"}],"responses":{"204":{"description":"Product deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Product has active installs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs":{"get":{"tags":["Installs"],"summary":"List installs in workspace","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of installs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Installs"],"summary":"Create product install","description":"Deploys a product to a region. Pass an `Idempotency-Key` header to safely retry on timeout.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":256,"description":"Unique key to prevent duplicate operations. If the same key is sent again, the existing workflow is returned instead of creating a new one.","example":"deploy-prod-2024-03-15"},"required":false,"description":"Unique key to prevent duplicate operations. If the same key is sent again, the existing workflow is returned instead of creating a new one.","name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"product_id":{"type":"string","minLength":1,"description":"Product ID"},"region_id":{"type":"string","minLength":1,"description":"Region ID"},"overrides":{"type":"array","items":{"type":"object","properties":{"template_helm_source_id":{"type":"string","minLength":1,"description":"Helm source ID to override"},"values":{"type":"object","additionalProperties":{"nullable":true},"description":"Helm values"}},"required":["template_helm_source_id","values"]},"description":"Initial value overrides per helm source"}},"required":["product_id","region_id"]}}}},"responses":{"202":{"description":"Install workflow started"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs/{id}":{"get":{"tags":["Installs"],"summary":"Get install details","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Install ID"},"required":true,"description":"Install ID","name":"id","in":"path"}],"responses":{"200":{"description":"Install details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Install"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Install not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Installs"],"summary":"Delete install","description":"Triggers async deletion of the install and its resources.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Install ID"},"required":true,"description":"Install ID","name":"id","in":"path"}],"responses":{"202":{"description":"Deletion started"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Install not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs/{id}/pods":{"get":{"tags":["Installs"],"summary":"List pods for install","description":"Returns pods and their containers for the install.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Install ID"},"required":true,"description":"Install ID","name":"id","in":"path"}],"responses":{"200":{"description":"List of pods","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Pod"}}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Install not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs/standalone":{"post":{"tags":["Installs"],"summary":"Create standalone install","description":"Deploys custom helm sources directly to clusters without a product. Pass an `Idempotency-Key` header to safely retry on timeout.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":256,"description":"Unique key to prevent duplicate operations. If the same key is sent again, the existing workflow is returned instead of creating a new one.","example":"deploy-prod-2024-03-15"},"required":false,"description":"Unique key to prevent duplicate operations. If the same key is sent again, the existing workflow is returned instead of creating a new one.","name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"my-redis"},"cluster_ids":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Cluster IDs to deploy to"},"helm_sources":{"type":"array","items":{"type":"object","properties":{"chart":{"type":"object","properties":{"repo_url":{"type":"string","minLength":1,"maxLength":2048},"chart":{"type":"string","minLength":1,"maxLength":100},"target_revision":{"type":"string","minLength":1,"maxLength":100},"path":{"type":"string","minLength":1,"maxLength":500}},"required":["repo_url","target_revision"]},"values":{"type":"object","additionalProperties":{"nullable":true}},"metadata":{"type":"object","additionalProperties":{"nullable":true}}},"required":["chart"]},"minItems":1}},"required":["name","cluster_ids","helm_sources"]}}}},"responses":{"202":{"description":"Install workflow started"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs/{id}/values":{"patch":{"tags":["Installs"],"summary":"Update install template values","description":"Updates template helm source values and regenerates the chart. Use this for standalone installs or to change the base values of a product install.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Install ID"},"required":true,"description":"Install ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"updates":{"type":"array","items":{"type":"object","properties":{"template_helm_source_id":{"type":"string","minLength":1,"description":"Helm source ID"},"values":{"type":"object","additionalProperties":{"nullable":true},"description":"Helm values"}},"required":["template_helm_source_id","values"]},"minItems":1}},"required":["updates"]}}}},"responses":{"202":{"description":"Update workflow started"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Install not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs/{id}/overrides":{"patch":{"tags":["Installs"],"summary":"Update install value overrides","description":"Applies per-install value overrides on top of the product base values. Does not regenerate the chart.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Install ID"},"required":true,"description":"Install ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"updates":{"type":"array","items":{"type":"object","properties":{"template_helm_source_id":{"type":"string","minLength":1,"description":"Helm source ID"},"values":{"type":"object","additionalProperties":{"nullable":true},"description":"Override values"}},"required":["template_helm_source_id","values"]},"minItems":1}},"required":["updates"]}}}},"responses":{"202":{"description":"Update workflow started"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Install not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/installs/{id}/logs":{"get":{"tags":["Installs"],"summary":"Stream install logs","description":"Streams logs from the install pods via Server-Sent Events. Use the `Accept: text/event-stream` header.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Install ID"},"required":true,"description":"Install ID","name":"id","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":253,"description":"Pod name (all pods if omitted)"},"required":false,"description":"Pod name (all pods if omitted)","name":"pod","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":253,"description":"Container name"},"required":false,"description":"Container name","name":"container","in":"query"},{"schema":{"type":"boolean","nullable":true,"default":true,"description":"Follow log output"},"required":false,"description":"Follow log output","name":"follow","in":"query"},{"schema":{"type":"integer","nullable":true,"description":"Lines to tail"},"required":false,"description":"Lines to tail","name":"tail","in":"query"},{"schema":{"type":"integer","nullable":true,"default":0,"description":"Only return logs newer than this many seconds"},"required":false,"description":"Only return logs newer than this many seconds","name":"since_seconds","in":"query"}],"responses":{"200":{"description":"Log stream (text/event-stream)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Install not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/regions":{"get":{"tags":["Regions"],"summary":"List regions in workspace","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of regions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegionList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Regions"],"summary":"Create region","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"us-east-1"},"icon":{"type":"string","maxLength":256,"format":"uri","description":"Icon URL"}},"required":["name"]}}}},"responses":{"201":{"description":"Region created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Region"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/registry/credentials":{"get":{"tags":["Registry"],"summary":"List registry credentials","description":"Returns credentials for the workspace. Credential secrets are never exposed.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Pagination cursor from previous response"},"required":false,"description":"Pagination cursor from previous response","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Items per page (1-100)","example":50},"required":false,"description":"Items per page (1-100)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistryCredentialList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Registry"],"summary":"Create registry credential","description":"Adds a registry credential to the workspace for OCI proxy authentication.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"GitHub Container Registry"},"registry_url":{"type":"string","minLength":1,"maxLength":2048,"example":"ghcr.io"},"type":{"type":"string","enum":["basic","token","oauth"],"description":"Auth type"},"credentials":{"type":"object","properties":{"username":{"type":"string","minLength":1,"maxLength":200},"password":{"type":"string","minLength":1,"maxLength":500},"token":{"type":"string","minLength":1,"maxLength":2000},"client_id":{"type":"string","minLength":1,"maxLength":200},"client_secret":{"type":"string","minLength":1,"maxLength":500},"token_url":{"type":"string","minLength":1,"maxLength":2048}},"description":"Auth credentials (type-dependent)"}},"required":["name","registry_url","type","credentials"]}}}},"responses":{"201":{"description":"Credential created"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or invalid workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/registry/credentials/{id}":{"delete":{"tags":["Registry"],"summary":"Delete registry credential","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Credential ID"},"required":true,"description":"Credential ID","name":"id","in":"path"}],"responses":{"204":{"description":"Credential deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Credential not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}} \ No newline at end of file diff --git a/internal/cmd/auth/auth.go b/internal/cmd/auth/auth.go deleted file mode 100644 index cedace4..0000000 --- a/internal/cmd/auth/auth.go +++ /dev/null @@ -1,204 +0,0 @@ -package auth - -import ( - "context" - "encoding/json" - "fmt" - "log/slog" - "net/http" - "strings" - - "github.com/cnap-tech/cli/internal/config" - "github.com/cnap-tech/cli/internal/useragent" - "github.com/spf13/cobra" -) - -func NewCmdAuth() *cobra.Command { - cmd := &cobra.Command{ - Use: "auth", - Short: "Manage authentication", - } - - cmd.AddCommand(newCmdLogin()) - cmd.AddCommand(newCmdLogout()) - cmd.AddCommand(newCmdStatus()) - - return cmd -} - -func newCmdLogin() *cobra.Command { - var token string - - cmd := &cobra.Command{ - Use: "login", - Short: "Authenticate with CNAP", - Long: `Authenticate via browser (default) or with a token. - -Without flags, opens your browser to authenticate via the device flow -and stores a session token. Sessions are long-lived and auto-refresh on use. - -With --token, stores the given token directly (PAT or session token). - -Create PATs at https://cnap.tech/settings/tokens`, - RunE: func(cmd *cobra.Command, args []string) error { - cfg, err := config.Load() - if err != nil { - return err - } - - if token != "" { - cfg.Auth.Token = token - if err := cfg.Save(); err != nil { - return fmt.Errorf("saving config: %w", err) - } - fmt.Println("Logged in successfully. Token saved to ~/.cnap/config.yaml") - return nil - } - - return runDeviceFlow(cmd.Context(), cfg) - }, - } - - cmd.Flags().StringVarP(&token, "token", "t", "", "API token (PAT or session token)") - - return cmd -} - -func newCmdLogout() *cobra.Command { - return &cobra.Command{ - Use: "logout", - Short: "Remove stored credentials", - RunE: func(cmd *cobra.Command, args []string) error { - cfg, err := config.Load() - if err != nil { - return err - } - - // Revoke session server-side if it's a session token - token := cfg.Token() - if token != "" && !strings.HasPrefix(token, "cnap_pat_") && !strings.HasPrefix(token, "eyJ") { - if err := revokeSession(cmd.Context(), cfg, token); err != nil { - slog.Debug("failed to revoke session server-side", "error", err) - } - } - - cfg.Auth.Token = "" - if err := cfg.Save(); err != nil { - return fmt.Errorf("saving config: %w", err) - } - - fmt.Println("Logged out. Credentials removed from ~/.cnap/config.yaml") - return nil - }, - } -} - -func newCmdStatus() *cobra.Command { - return &cobra.Command{ - Use: "status", - Short: "Show authentication status", - RunE: func(cmd *cobra.Command, args []string) error { - cfg, err := config.Load() - if err != nil { - return err - } - - token := cfg.Token() - if token == "" { - fmt.Println("Not authenticated. Run: cnap auth login") - return nil - } - - tokenType := detectTokenType(token) - - // Show prefix only for security - prefix := token - if len(prefix) > 16 { - prefix = prefix[:16] + "..." - } - - fmt.Printf("Token type: %s\n", tokenType) - fmt.Printf("Token: %s\n", prefix) - fmt.Printf("API URL: %s\n", cfg.BaseURL()) - fmt.Printf("Auth URL: %s\n", cfg.AuthBaseURL()) - - if tokenType == "Session token" { - if err := checkSessionStatus(cmd.Context(), cfg, token); err != nil { - fmt.Printf("Session status: invalid or expired (%v)\n", err) - fmt.Println("Run 'cnap auth login' to re-authenticate.") - } - } - - if cfg.ActiveWorkspace != "" { - fmt.Printf("Active workspace: %s\n", cfg.ActiveWorkspace) - } else { - fmt.Println("No active workspace. Run: cnap workspaces switch ") - } - - return nil - }, - } -} - -func detectTokenType(token string) string { - switch { - case strings.HasPrefix(token, "cnap_pat_"): - return "Personal Access Token (PAT)" - case strings.HasPrefix(token, "eyJ"): - return "JWT" - default: - return "Session token" - } -} - -func checkSessionStatus(ctx context.Context, cfg *config.Config, token string) error { - authURL := cfg.AuthBaseURL() - req, err := http.NewRequestWithContext(ctx, "GET", authURL+"/api/auth/get-session", nil) - if err != nil { - return err - } - req.Header.Set("Authorization", "Bearer "+token) - req.Header.Set("User-Agent", useragent.String()) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() //nolint:errcheck - - if resp.StatusCode != 200 { - return fmt.Errorf("HTTP %d", resp.StatusCode) - } - - var result struct { - Session *struct { - ExpiresAt string `json:"expiresAt"` - } `json:"session"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return err - } - if result.Session == nil { - return fmt.Errorf("session not found or expired") - } - - fmt.Printf("Session status: active (expires: %s)\n", result.Session.ExpiresAt) - return nil -} - -func revokeSession(ctx context.Context, cfg *config.Config, token string) error { - authURL := cfg.AuthBaseURL() - req, err := http.NewRequestWithContext(ctx, "POST", authURL+"/api/auth/sign-out", nil) - if err != nil { - return err - } - req.Header.Set("Authorization", "Bearer "+token) - req.Header.Set("User-Agent", useragent.String()) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() //nolint:errcheck - return nil -} diff --git a/internal/cmd/auth/device.go b/internal/cmd/auth/device.go deleted file mode 100644 index 3a565c6..0000000 --- a/internal/cmd/auth/device.go +++ /dev/null @@ -1,212 +0,0 @@ -// Device authorization flow (RFC 8628) for browser-based CLI authentication. -// -// Flow: -// 1. POST /api/auth/device/code - device_code + user_code -// 2. Open browser to /device?user_code=X - user approves -// 3. POST /api/auth/device/token (poll) - session token (access_token) -// 4. Store session token in ~/.cnap/config.yaml -// -// The session token is sent as a Bearer token in subsequent API requests. -// The public API middleware validates it via BetterAuth's get-session endpoint. -// Sessions are valid for 1 year and auto-refresh on use, so active users never expire. -// -// For CI/CD, PATs (cnap_pat_...) are still supported via --token flag. -// -// See also: public-api.middleware.ts (server-side token verification) -package auth - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "log/slog" - "net/http" - "os/exec" - "runtime" - "time" - - "github.com/cnap-tech/cli/internal/config" - "github.com/cnap-tech/cli/internal/useragent" -) - -const clientID = "cnap-cli" - -type deviceCodeResponse struct { - DeviceCode string `json:"device_code"` - UserCode string `json:"user_code"` - VerificationURI string `json:"verification_uri"` - VerificationURIComplete string `json:"verification_uri_complete"` - ExpiresIn int `json:"expires_in"` - Interval int `json:"interval"` -} - -type deviceTokenResponse struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - ExpiresIn int `json:"expires_in"` - Scope string `json:"scope"` -} - -type deviceTokenError struct { - Error string `json:"error"` - ErrorDescription string `json:"error_description"` -} - -func runDeviceFlow(ctx context.Context, cfg *config.Config) error { - authURL := cfg.AuthBaseURL() - slog.Debug("starting device flow", "auth_url", authURL, "api_url", cfg.BaseURL()) - - // Step 1: Request device code - code, err := requestDeviceCode(ctx, authURL) - if err != nil { - return fmt.Errorf("requesting device code: %w", err) - } - - // Step 2: Display instructions and open browser - verificationURL := fmt.Sprintf("%s/device?user_code=%s", authURL, code.UserCode) - fmt.Printf("\nTo authenticate, open this URL in your browser:\n\n") - fmt.Printf(" %s\n\n", verificationURL) - fmt.Printf("And verify this code: %s\n\n", formatUserCode(code.UserCode)) - - if err := openBrowser(verificationURL); err != nil { - fmt.Println("(Could not open browser automatically)") - } else { - fmt.Println("Browser opened. Waiting for authorization...") - } - - // Step 3: Poll for session token - interval := time.Duration(code.Interval) * time.Second - if interval < 5*time.Second { - interval = 5 * time.Second - } - deadline := time.Now().Add(time.Duration(code.ExpiresIn) * time.Second) - - sessionToken, err := pollForToken(ctx, authURL, code.DeviceCode, interval, deadline) - if err != nil { - return err - } - - // Step 4: Store session token directly - cfg.Auth.Token = sessionToken - if err := cfg.Save(); err != nil { - return fmt.Errorf("saving config: %w", err) - } - - fmt.Println("\nLogged in successfully. Session token saved to ~/.cnap/config.yaml") - return nil -} - -func requestDeviceCode(ctx context.Context, authURL string) (*deviceCodeResponse, error) { - body, _ := json.Marshal(map[string]string{ - "client_id": clientID, - }) - req, err := http.NewRequestWithContext(ctx, "POST", authURL+"/api/auth/device/code", bytes.NewReader(body)) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("User-Agent", useragent.String()) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() //nolint:errcheck - - if resp.StatusCode != 200 { - data, _ := io.ReadAll(resp.Body) - return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(data)) - } - - var result deviceCodeResponse - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return nil, err - } - return &result, nil -} - -func pollForToken(ctx context.Context, authURL, deviceCode string, interval time.Duration, deadline time.Time) (string, error) { - for { - if time.Now().After(deadline) { - return "", fmt.Errorf("device authorization expired — please try again") - } - - select { - case <-ctx.Done(): - return "", ctx.Err() - case <-time.After(interval): - } - - body, _ := json.Marshal(map[string]string{ - "grant_type": "urn:ietf:params:oauth:grant-type:device_code", - "device_code": deviceCode, - "client_id": clientID, - }) - - req, err := http.NewRequestWithContext(ctx, "POST", authURL+"/api/auth/device/token", bytes.NewReader(body)) - if err != nil { - return "", fmt.Errorf("polling for token: %w", err) - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("User-Agent", useragent.String()) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return "", fmt.Errorf("polling for token: %w", err) - } - - data, _ := io.ReadAll(resp.Body) - resp.Body.Close() //nolint:errcheck - - if resp.StatusCode == 200 { - var tokenResp deviceTokenResponse - if err := json.Unmarshal(data, &tokenResp); err != nil { - return "", fmt.Errorf("parsing token response: %w", err) - } - return tokenResp.AccessToken, nil - } - - var errResp deviceTokenError - if err := json.Unmarshal(data, &errResp); err != nil { - return "", fmt.Errorf("parsing error response: %w", err) - } - - switch errResp.Error { - case "authorization_pending": - continue - case "slow_down": - interval += 5 * time.Second - continue - case "expired_token": - return "", fmt.Errorf("device code expired — please try again") - case "access_denied": - return "", fmt.Errorf("authorization was denied") - default: - return "", fmt.Errorf("unexpected error: %s — %s", errResp.Error, errResp.ErrorDescription) - } - } -} - -func formatUserCode(code string) string { - if len(code) == 8 { - return code[:4] + "-" + code[4:] - } - return code -} - -func openBrowser(url string) error { - var cmd *exec.Cmd - switch runtime.GOOS { - case "darwin": - cmd = exec.Command("open", url) - case "linux": - cmd = exec.Command("xdg-open", url) - case "windows": - cmd = exec.Command("cmd", "/c", "start", url) - default: - return fmt.Errorf("unsupported platform: %s", runtime.GOOS) - } - return cmd.Start() -} diff --git a/internal/cmd/clusters/clusters.go b/internal/cmd/clusters/clusters.go deleted file mode 100644 index 93e6df4..0000000 --- a/internal/cmd/clusters/clusters.go +++ /dev/null @@ -1,379 +0,0 @@ -package clusters - -import ( - "context" - "encoding/json" - "fmt" - "io" - "os" - "strings" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/spf13/cobra" -) - -func NewCmdClusters() *cobra.Command { - cmd := &cobra.Command{ - Use: "clusters", - Aliases: []string{"cluster", "cl"}, - Short: "Manage clusters", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdGet()) - cmd.AddCommand(newCmdUpdate()) - cmd.AddCommand(newCmdDelete()) - cmd.AddCommand(newCmdKubeconfig()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List clusters in the active workspace", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - params := &api.GetV1ClustersParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1ClustersWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching clusters: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - header := []string{"ID", "NAME", "REGION", "TYPE", "STATUS"} - var rows [][]string - for _, c := range resp.JSON200.Data { - clusterType := "imported" - status := "-" - if c.Kaas != nil { - clusterType = "kaas" - status = string(c.Kaas.Status) - } - rows = append(rows, []string{c.Id, c.Name, c.RegionId, clusterType, status}) - } - - if len(rows) == 0 { - fmt.Println("No clusters found in this workspace.") - return nil - } - - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdGet() *cobra.Command { - return &cobra.Command{ - Use: "get [cluster-id]", - Short: "Get cluster details", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - clusterID := "" - if len(args) > 0 { - clusterID = args[0] - } else { - clusterID, err = pickCluster(cmd.Context(), client) - if err != nil { - return err - } - } - - resp, err := client.GetV1ClustersIdWithResponse(cmd.Context(), clusterID) - if err != nil { - return fmt.Errorf("fetching cluster: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - c := resp.JSON200 - clusterType := "imported" - status := "-" - if c.Kaas != nil { - clusterType = "kaas" - status = string(c.Kaas.Status) - if c.Kaas.StatusMessage != nil { - status += " (" + *c.Kaas.StatusMessage + ")" - } - } - - output.PrintTable( - []string{"FIELD", "VALUE"}, - [][]string{ - {"ID", c.Id}, - {"Name", c.Name}, - {"Workspace", c.WorkspaceId}, - {"Region", c.RegionId}, - {"Type", clusterType}, - {"Status", status}, - }, - ) - return nil - }, - } -} - -func newCmdUpdate() *cobra.Command { - var name, regionID string - - cmd := &cobra.Command{ - Use: "update [cluster-id]", - Short: "Update cluster name or region", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - if name == "" && regionID == "" { - return fmt.Errorf("at least one of --name or --region is required") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - clusterID := "" - if len(args) > 0 { - clusterID = args[0] - } else { - clusterID, err = pickCluster(cmd.Context(), client) - if err != nil { - return err - } - } - - body := api.PatchV1ClustersIdJSONRequestBody{} - if name != "" { - body.Name = &name - } - if regionID != "" { - body.RegionId = ®ionID - } - - resp, err := client.PatchV1ClustersIdWithResponse(cmd.Context(), clusterID, body) - if err != nil { - return fmt.Errorf("updating cluster: %w", err) - } - if resp.JSON200 == nil { - return fmt.Errorf("unexpected response: %s", resp.Status()) - } - - fmt.Printf("Cluster %s updated.\n", resp.JSON200.Name) - return nil - }, - } - - cmd.Flags().StringVar(&name, "name", "", "New cluster name") - cmd.Flags().StringVar(®ionID, "region", "", "New region ID") - - return cmd -} - -func newCmdDelete() *cobra.Command { - var yes bool - - cmd := &cobra.Command{ - Use: "delete [cluster-id]", - Short: "Delete a cluster", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - clusterID := "" - if len(args) > 0 { - clusterID = args[0] - } else { - clusterID, err = pickCluster(cmd.Context(), client) - if err != nil { - return err - } - } - - if !yes { - if !prompt.IsInteractive() { - return fmt.Errorf("use --yes to confirm deletion in non-interactive mode") - } - confirmed, err := prompt.Confirm(fmt.Sprintf("Delete cluster %s?", clusterID)) - if err != nil { - return err - } - if !confirmed { - fmt.Println("Cancelled.") - return nil - } - } - - resp, err := client.DeleteV1ClustersIdWithResponse(cmd.Context(), clusterID) - if err != nil { - return fmt.Errorf("deleting cluster: %w", err) - } - if resp.HTTPResponse.StatusCode != 204 { - return fmt.Errorf("unexpected response: %s", resp.Status()) - } - - fmt.Printf("Cluster %s deleted.\n", clusterID) - return nil - }, - } - - cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip confirmation prompt") - - return cmd -} - -func newCmdKubeconfig() *cobra.Command { - var outputFile string - - cmd := &cobra.Command{ - Use: "kubeconfig [cluster-id]", - Short: "Get cluster admin kubeconfig", - Long: "Downloads the admin kubeconfig for a KaaS-managed cluster. The cluster must be running.", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - clusterID := "" - if len(args) > 0 { - clusterID = args[0] - } else { - clusterID, err = pickCluster(cmd.Context(), client) - if err != nil { - return err - } - } - - resp, err := client.GetV1ClustersIdKubeconfig(cmd.Context(), clusterID) - if err != nil { - return fmt.Errorf("fetching kubeconfig: %w", err) - } - defer func() { _ = resp.Body.Close() }() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("reading response: %w", err) - } - - if resp.StatusCode != 200 { - var apiErr api.Error - if json.Unmarshal(body, &apiErr) == nil { - return fmt.Errorf("%s", apiErr.Error.Message) - } - return fmt.Errorf("unexpected response: %s", resp.Status) - } - - if outputFile != "" { - if err := os.WriteFile(outputFile, body, 0600); err != nil { - return fmt.Errorf("writing kubeconfig: %w", err) - } - fmt.Printf("Kubeconfig written to %s\n", outputFile) - return nil - } - - fmt.Print(string(body)) - return nil - }, - } - - cmd.Flags().StringVarP(&outputFile, "output", "o", "", "Write kubeconfig to file (mode 0600)") - - return cmd -} - -// pickCluster shows an interactive cluster picker. Returns the selected cluster ID. -func pickCluster(ctx context.Context, client *api.ClientWithResponses) (string, error) { - limit := 100 - listResp, err := client.GetV1ClustersWithResponse(ctx, &api.GetV1ClustersParams{Limit: &limit}) - if err != nil { - return "", fmt.Errorf("fetching clusters: %w", err) - } - if listResp.JSON200 == nil { - return "", apiError(listResp.Status(), listResp.JSON401, listResp.JSON403) - } - if len(listResp.JSON200.Data) == 0 { - return "", fmt.Errorf("no clusters found in this workspace") - } - options := make([]prompt.SelectOption, len(listResp.JSON200.Data)) - for i, c := range listResp.JSON200.Data { - options[i] = prompt.SelectOption{Label: c.Name + " (" + c.Id + ")", Value: c.Id} - } - return prompt.Select("Select a cluster", options) -} - -func apiError(status string, errs ...*api.Error) error { - for _, e := range errs { - if e != nil { - parts := []string{e.Error.Message} - if e.Error.Suggestion != nil { - parts = append(parts, *e.Error.Suggestion) - } - return fmt.Errorf("%s", strings.Join(parts, ". ")) - } - } - return fmt.Errorf("unexpected response: %s", status) -} diff --git a/internal/cmd/installs/exec.go b/internal/cmd/installs/exec.go deleted file mode 100644 index 259ab9c..0000000 --- a/internal/cmd/installs/exec.go +++ /dev/null @@ -1,245 +0,0 @@ -package installs - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/url" - "os" - "os/signal" - "strings" - - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/config" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/cnap-tech/cli/internal/useragent" - "github.com/coder/websocket" - "github.com/spf13/cobra" - "golang.org/x/term" -) - -func newCmdExec() *cobra.Command { - var pod, container, shell string - - cmd := &cobra.Command{ - Use: "exec [install-id]", - Short: "Open an interactive shell in a pod container", - Long: `Opens a WebSocket connection to a pod container for interactive shell access. - -When run interactively without arguments, shows pickers to select an -install, pod, and container. In non-interactive environments, all -arguments and flags are required.`, - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - var installID string - - if len(args) > 0 { - installID = args[0] - } else { - installID, err = pickInstall(cmd.Context(), client) - if err != nil { - return err - } - } - - // Interactive pod picker if --pod not set - if pod == "" && prompt.IsInteractive() { - podsResp, err := client.GetV1InstallsIdPodsWithResponse(cmd.Context(), installID) - if err != nil { - return fmt.Errorf("fetching pods: %w", err) - } - if podsResp.JSON200 != nil && len(podsResp.JSON200.Data) > 0 { - podOpts := make([]prompt.SelectOption, len(podsResp.JSON200.Data)) - for i, p := range podsResp.JSON200.Data { - podOpts[i] = prompt.SelectOption{ - Label: p.Name + " [" + strings.Join(p.Containers, ", ") + "]", - Value: p.Name, - } - } - - pod, err = prompt.Select("Select a pod", podOpts) - if err != nil { - return err - } - - // Interactive container picker if pod has multiple containers - if container == "" { - for _, p := range podsResp.JSON200.Data { - if p.Name == pod { - if len(p.Containers) > 1 { - containerOpts := make([]prompt.SelectOption, len(p.Containers)) - for i, c := range p.Containers { - containerOpts[i] = prompt.SelectOption{Label: c, Value: c} - } - container, err = prompt.Select("Select a container", containerOpts) - if err != nil { - return err - } - } else if len(p.Containers) == 1 { - container = p.Containers[0] - } - break - } - } - } - } - } - - if pod == "" || container == "" { - return fmt.Errorf("--pod and --container are required") - } - - return runExec(cmd.Context(), cfg, installID, pod, container, shell) - }, - } - - cmd.Flags().StringVar(&pod, "pod", "", "Pod name") - cmd.Flags().StringVar(&container, "container", "", "Container name") - cmd.Flags().StringVar(&shell, "shell", "/bin/sh", "Shell to use") - - return cmd -} - -// runExec connects to the WebSocket exec endpoint and bridges it to the local terminal. -func runExec(parentCtx context.Context, cfg *config.Config, installID, podName, containerName, shell string) error { - // Build WebSocket URL from the dashboard/auth URL (where exec handler lives) - baseURL := cfg.AuthBaseURL() - u, err := url.Parse(baseURL) - if err != nil { - return fmt.Errorf("parsing auth URL: %w", err) - } - - // Convert http(s) to ws(s) - switch u.Scheme { - case "https": - u.Scheme = "wss" - default: - u.Scheme = "ws" - } - u.Path = fmt.Sprintf("/api/exec/installs/%s/shell", installID) - q := u.Query() - q.Set("podName", podName) - q.Set("containerName", containerName) - q.Set("shell", shell) - u.RawQuery = q.Encode() - - ctx, cancel := context.WithCancel(parentCtx) - defer cancel() - - // Connect - conn, resp, err := websocket.Dial(ctx, u.String(), &websocket.DialOptions{ - HTTPHeader: http.Header{ - "Authorization": []string{"Bearer " + cfg.Token()}, - "User-Agent": []string{useragent.String()}, - }, - }) - if err != nil { - if resp != nil { - return fmt.Errorf("WebSocket connection failed (HTTP %d): %w", resp.StatusCode, err) - } - return fmt.Errorf("WebSocket connection failed: %w", err) - } - defer func() { _ = conn.CloseNow() }() - - // Put terminal in raw mode - fd := int(os.Stdin.Fd()) - if !term.IsTerminal(fd) { - return fmt.Errorf("stdin is not a terminal") - } - oldState, err := term.MakeRaw(fd) - if err != nil { - return fmt.Errorf("setting raw terminal mode: %w", err) - } - defer func() { _ = term.Restore(fd, oldState) }() - - // Send initial terminal size - sendResize(ctx, conn) - - // Start platform-specific resize monitoring (SIGWINCH on Unix, polling on Windows) - resizeStop := make(chan struct{}) - go monitorResize(ctx, conn, resizeStop) - - done := make(chan struct{}) - - // Goroutine: read from WebSocket → write to stdout - go func() { - defer close(done) - for { - _, data, err := conn.Read(ctx) - if err != nil { - return - } - var msg wsMessage - if json.Unmarshal(data, &msg) != nil { - continue - } - switch msg.Type { - case "output": - _, _ = os.Stdout.Write([]byte(msg.Data)) - case "error": - _, _ = fmt.Fprintf(os.Stderr, "\r\nError: %s\r\n", msg.Message) - case "close": - return - } - } - }() - - // Goroutine: read from stdin → send to WebSocket - go func() { - buf := make([]byte, 1024) - for { - n, err := os.Stdin.Read(buf) - if err != nil || n == 0 { - return - } - msg, _ := json.Marshal(wsMessage{Type: "input", Data: string(buf[:n])}) - if conn.Write(ctx, websocket.MessageText, msg) != nil { - return - } - } - }() - - // Goroutine: handle Ctrl+C - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, os.Interrupt) - defer signal.Stop(sigCh) - - go func() { - select { - case <-sigCh: - _ = conn.Close(websocket.StatusNormalClosure, "") - case <-done: - } - close(resizeStop) - }() - - <-done - return nil -} - -type wsMessage struct { - Type string `json:"type"` - Data string `json:"data,omitempty"` - Message string `json:"message,omitempty"` - Cols int `json:"cols,omitempty"` - Rows int `json:"rows,omitempty"` -} - -func sendResize(ctx context.Context, conn *websocket.Conn) { - w, h, err := term.GetSize(int(os.Stdout.Fd())) - if err != nil { - return - } - msg, _ := json.Marshal(wsMessage{Type: "resize", Cols: w, Rows: h}) - _ = conn.Write(ctx, websocket.MessageText, msg) -} diff --git a/internal/cmd/installs/exec_unix.go b/internal/cmd/installs/exec_unix.go deleted file mode 100644 index 6a5523f..0000000 --- a/internal/cmd/installs/exec_unix.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build !windows - -package installs - -import ( - "context" - "os" - "os/signal" - "syscall" - - "github.com/coder/websocket" -) - -// monitorResize listens for SIGWINCH signals and sends resize events over the WebSocket. -func monitorResize(ctx context.Context, conn *websocket.Conn, stop <-chan struct{}) { - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGWINCH) - defer signal.Stop(sigCh) - - for { - select { - case <-sigCh: - sendResize(ctx, conn) - case <-stop: - return - } - } -} diff --git a/internal/cmd/installs/exec_windows.go b/internal/cmd/installs/exec_windows.go deleted file mode 100644 index 5c825ec..0000000 --- a/internal/cmd/installs/exec_windows.go +++ /dev/null @@ -1,39 +0,0 @@ -package installs - -import ( - "context" - "os" - "time" - - "github.com/coder/websocket" - "golang.org/x/term" -) - -// monitorResize polls terminal size every 250ms and sends resize events when dimensions change. -// Windows has no SIGWINCH equivalent, so polling is the standard approach (used by kubectl). -func monitorResize(ctx context.Context, conn *websocket.Conn, stop <-chan struct{}) { - fd := int(os.Stdout.Fd()) - w, h, err := term.GetSize(fd) - if err != nil { - return - } - - ticker := time.NewTicker(250 * time.Millisecond) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - newW, newH, err := term.GetSize(fd) - if err != nil { - continue - } - if newW != w || newH != h { - w, h = newW, newH - sendResize(ctx, conn) - } - case <-stop: - return - } - } -} diff --git a/internal/cmd/installs/installs.go b/internal/cmd/installs/installs.go deleted file mode 100644 index b4c186c..0000000 --- a/internal/cmd/installs/installs.go +++ /dev/null @@ -1,677 +0,0 @@ -package installs - -import ( - "bufio" - "context" - "encoding/json" - "fmt" - "os" - "os/signal" - "strings" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/spf13/cobra" - "gopkg.in/yaml.v3" -) - -func NewCmdInstalls() *cobra.Command { - cmd := &cobra.Command{ - Use: "installs", - Aliases: []string{"install", "inst"}, - Short: "Manage installs", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdGet()) - cmd.AddCommand(newCmdCreate()) - cmd.AddCommand(newCmdDelete()) - cmd.AddCommand(newCmdUpdateValues()) - cmd.AddCommand(newCmdUpdateOverrides()) - cmd.AddCommand(newCmdPods()) - cmd.AddCommand(newCmdLogs()) - cmd.AddCommand(newCmdExec()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List installs in the active workspace", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - params := &api.GetV1InstallsParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1InstallsWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching installs: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - if len(resp.JSON200.Data) == 0 { - fmt.Println("No installs found in this workspace.") - return nil - } - - header := []string{"ID", "NAME", "PRODUCT", "CLUSTER", "CREATED"} - var rows [][]string - for _, i := range resp.JSON200.Data { - name := "-" - if i.Name != nil { - name = *i.Name - } - productId := "-" - if i.ProductId != nil { - productId = *i.ProductId - } - rows = append(rows, []string{i.Id, name, productId, i.ClusterId, formatTime(i.CreatedAt)}) - } - - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdGet() *cobra.Command { - return &cobra.Command{ - Use: "get [install-id]", - Short: "Get install details", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - installID := "" - if len(args) > 0 { - installID = args[0] - } else { - installID, err = pickInstall(cmd.Context(), client) - if err != nil { - return err - } - } - - resp, err := client.GetV1InstallsIdWithResponse(cmd.Context(), installID) - if err != nil { - return fmt.Errorf("fetching install: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - i := resp.JSON200 - - output.PrintTable( - []string{"FIELD", "VALUE"}, - [][]string{ - {"ID", i.Id}, - {"Name", deref(i.Name)}, - {"Workspace", i.WorkspaceId}, - {"Product", deref(i.ProductId)}, - {"Template", deref(i.TemplateId)}, - {"Cluster", i.ClusterId}, - }, - ) - return nil - }, - } -} - -func newCmdDelete() *cobra.Command { - var yes bool - - cmd := &cobra.Command{ - Use: "delete [install-id]", - Short: "Delete an install", - Long: "Triggers an async deletion workflow that removes the ArgoCD application and install record.", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - installID := "" - if len(args) > 0 { - installID = args[0] - } else { - installID, err = pickInstall(cmd.Context(), client) - if err != nil { - return err - } - } - - if !yes { - if !prompt.IsInteractive() { - return fmt.Errorf("use --yes to confirm deletion in non-interactive mode") - } - confirmed, err := prompt.Confirm(fmt.Sprintf("Delete install %s?", installID)) - if err != nil { - return err - } - if !confirmed { - fmt.Println("Cancelled.") - return nil - } - } - - resp, err := client.DeleteV1InstallsIdWithResponse(cmd.Context(), installID) - if err != nil { - return fmt.Errorf("deleting install: %w", err) - } - if resp.HTTPResponse.StatusCode != 202 { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - fmt.Printf("Install %s deletion started.\n", installID) - return nil - }, - } - - cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip confirmation prompt") - - return cmd -} - -func newCmdCreate() *cobra.Command { - var productID, regionID string - - cmd := &cobra.Command{ - Use: "create", - Short: "Create a product install", - Long: "Deploys a product to a region. Starts an async workflow.", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - body := api.PostV1InstallsJSONRequestBody{ - ProductId: productID, - RegionId: regionID, - } - - resp, err := client.PostV1InstallsWithResponse(cmd.Context(), nil, body) - if err != nil { - return fmt.Errorf("creating install: %w", err) - } - if resp.HTTPResponse.StatusCode != 202 { - return apiError(resp.Status(), resp.JSON401, resp.JSON403, resp.JSON422) - } - - fmt.Println("Install workflow started.") - return nil - }, - } - - cmd.Flags().StringVar(&productID, "product", "", "Product ID (required)") - cmd.Flags().StringVar(®ionID, "region", "", "Region ID (required)") - _ = cmd.MarkFlagRequired("product") - _ = cmd.MarkFlagRequired("region") - - return cmd -} - -func newCmdUpdateValues() *cobra.Command { - var sourceID, valuesFile string - - cmd := &cobra.Command{ - Use: "update-values [install-id]", - Short: "Update install template values", - Long: "Updates template helm source values and regenerates the chart.", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - installID := "" - if len(args) > 0 { - installID = args[0] - } else { - installID, err = pickInstall(cmd.Context(), client) - if err != nil { - return err - } - } - - values, err := readValuesFile(valuesFile) - if err != nil { - return err - } - - body := api.PatchV1InstallsIdValuesJSONRequestBody{ - Updates: []struct { - TemplateHelmSourceId string `json:"template_helm_source_id"` - Values map[string]*interface{} `json:"values"` - }{ - { - TemplateHelmSourceId: sourceID, - Values: values, - }, - }, - } - - resp, err := client.PatchV1InstallsIdValuesWithResponse(cmd.Context(), installID, body) - if err != nil { - return fmt.Errorf("updating install values: %w", err) - } - if resp.HTTPResponse.StatusCode != 202 { - return apiError(resp.Status(), resp.JSON401, resp.JSON404, resp.JSON422) - } - - fmt.Println("Install values update started.") - return nil - }, - } - - cmd.Flags().StringVar(&sourceID, "source", "", "Helm source ID (required)") - cmd.Flags().StringVarP(&valuesFile, "values", "f", "", "Values YAML/JSON file (required)") - _ = cmd.MarkFlagRequired("source") - _ = cmd.MarkFlagRequired("values") - - return cmd -} - -func newCmdUpdateOverrides() *cobra.Command { - var sourceID, valuesFile string - - cmd := &cobra.Command{ - Use: "update-overrides [install-id]", - Short: "Update install value overrides", - Long: "Applies per-install value overrides on top of product base values.", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - installID := "" - if len(args) > 0 { - installID = args[0] - } else { - installID, err = pickInstall(cmd.Context(), client) - if err != nil { - return err - } - } - - values, err := readValuesFile(valuesFile) - if err != nil { - return err - } - - body := api.PatchV1InstallsIdOverridesJSONRequestBody{ - Updates: []struct { - TemplateHelmSourceId string `json:"template_helm_source_id"` - Values map[string]*interface{} `json:"values"` - }{ - { - TemplateHelmSourceId: sourceID, - Values: values, - }, - }, - } - - resp, err := client.PatchV1InstallsIdOverridesWithResponse(cmd.Context(), installID, body) - if err != nil { - return fmt.Errorf("updating install overrides: %w", err) - } - if resp.HTTPResponse.StatusCode != 202 { - return apiError(resp.Status(), resp.JSON401, resp.JSON404, resp.JSON422) - } - - fmt.Println("Install overrides update started.") - return nil - }, - } - - cmd.Flags().StringVar(&sourceID, "source", "", "Helm source ID (required)") - cmd.Flags().StringVarP(&valuesFile, "values", "f", "", "Values YAML/JSON file (required)") - _ = cmd.MarkFlagRequired("source") - _ = cmd.MarkFlagRequired("values") - - return cmd -} - -func readValuesFile(path string) (map[string]*interface{}, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("reading values file: %w", err) - } - - var raw map[string]interface{} - - // Try JSON first, then YAML - if err := json.Unmarshal(data, &raw); err != nil { - if err := yaml.Unmarshal(data, &raw); err != nil { - return nil, fmt.Errorf("parsing values file (expected JSON or YAML): %w", err) - } - } - - // Convert to map[string]*interface{} for the API client - result := make(map[string]*interface{}, len(raw)) - for k, v := range raw { - val := v - result[k] = &val - } - return result, nil -} - -func newCmdPods() *cobra.Command { - return &cobra.Command{ - Use: "pods [install-id]", - Short: "List pods for an install", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - installID := "" - if len(args) > 0 { - installID = args[0] - } else { - installID, err = pickInstall(cmd.Context(), client) - if err != nil { - return err - } - } - - resp, err := client.GetV1InstallsIdPodsWithResponse(cmd.Context(), installID) - if err != nil { - return fmt.Errorf("fetching pods: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200.Data) - } - - if len(resp.JSON200.Data) == 0 { - fmt.Println("No pods found for this install.") - return nil - } - - header := []string{"POD", "CONTAINERS"} - var rows [][]string - for _, p := range resp.JSON200.Data { - rows = append(rows, []string{p.Name, strings.Join(p.Containers, ", ")}) - } - - output.PrintTable(header, rows) - return nil - }, - } -} - -func newCmdLogs() *cobra.Command { - var pod, container string - var follow bool - var tail, sinceSeconds int - - cmd := &cobra.Command{ - Use: "logs [install-id]", - Short: "Stream logs from an install", - Long: `Streams logs from install pods via Server-Sent Events. - -When run interactively without arguments, shows pickers to select an -install, pod, and container. In non-interactive environments (CI, pipes), -the install ID argument is required.`, - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - var installID string - - if len(args) > 0 { - installID = args[0] - } else { - // Interactive install picker - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - limit := 100 - listResp, err := client.GetV1InstallsWithResponse(cmd.Context(), &api.GetV1InstallsParams{Limit: &limit}) - if err != nil { - return fmt.Errorf("fetching installs: %w", err) - } - if listResp.JSON200 == nil { - return apiError(listResp.Status(), listResp.JSON401, listResp.JSON403) - } - if len(listResp.JSON200.Data) == 0 { - return fmt.Errorf("no installs found in this workspace") - } - - options := make([]prompt.SelectOption, len(listResp.JSON200.Data)) - for i, inst := range listResp.JSON200.Data { - label := inst.Id - if inst.Name != nil { - label = *inst.Name + " (" + inst.Id + ")" - } - options[i] = prompt.SelectOption{Label: label, Value: inst.Id} - } - - installID, err = prompt.Select("Select an install", options) - if err != nil { - return err - } - } - - // Interactive pod picker if --pod not set - if pod == "" && prompt.IsInteractive() { - podsResp, err := client.GetV1InstallsIdPodsWithResponse(cmd.Context(), installID) - if err != nil { - return fmt.Errorf("fetching pods: %w", err) - } - if podsResp.JSON200 != nil && len(podsResp.JSON200.Data) > 0 { - podOpts := make([]prompt.SelectOption, len(podsResp.JSON200.Data)) - for i, p := range podsResp.JSON200.Data { - podOpts[i] = prompt.SelectOption{ - Label: p.Name + " [" + strings.Join(p.Containers, ", ") + "]", - Value: p.Name, - } - } - - pod, err = prompt.Select("Select a pod", podOpts) - if err != nil { - return err - } - - // Interactive container picker if pod has multiple containers - if container == "" { - for _, p := range podsResp.JSON200.Data { - if p.Name == pod && len(p.Containers) > 1 { - containerOpts := make([]prompt.SelectOption, len(p.Containers)) - for i, c := range p.Containers { - containerOpts[i] = prompt.SelectOption{Label: c, Value: c} - } - container, err = prompt.Select("Select a container", containerOpts) - if err != nil { - return err - } - break - } - } - } - } - } - - params := &api.GetV1InstallsIdLogsParams{ - Follow: &follow, - } - if pod != "" { - params.Pod = &pod - } - if container != "" { - params.Container = &container - } - if tail > 0 { - params.Tail = &tail - } - if sinceSeconds > 0 { - params.SinceSeconds = &sinceSeconds - } - - ctx, cancel := signal.NotifyContext(cmd.Context(), os.Interrupt) - defer cancel() - - // Use raw client to get streaming response - resp, err := client.GetV1InstallsIdLogs(ctx, installID, params) - if err != nil { - return fmt.Errorf("streaming logs: %w", err) - } - defer func() { _ = resp.Body.Close() }() - - if resp.StatusCode != 200 { - return fmt.Errorf("unexpected response: %s", resp.Status) - } - - // Read SSE stream line by line - scanner := bufio.NewScanner(resp.Body) - for scanner.Scan() { - line := scanner.Text() - // SSE format: "data: " - if strings.HasPrefix(line, "data: ") { - fmt.Println(line[6:]) - } - } - - return scanner.Err() - }, - } - - cmd.Flags().StringVar(&pod, "pod", "", "Pod name (all pods if omitted)") - cmd.Flags().StringVar(&container, "container", "", "Container name") - cmd.Flags().BoolVarP(&follow, "follow", "f", true, "Follow log output") - cmd.Flags().IntVar(&tail, "tail", 0, "Number of lines to tail") - cmd.Flags().IntVar(&sinceSeconds, "since", 0, "Only return logs newer than this many seconds") - - return cmd -} - -// pickInstall shows an interactive install picker. Returns the selected install ID. -func pickInstall(ctx context.Context, client *api.ClientWithResponses) (string, error) { - limit := 100 - listResp, err := client.GetV1InstallsWithResponse(ctx, &api.GetV1InstallsParams{Limit: &limit}) - if err != nil { - return "", fmt.Errorf("fetching installs: %w", err) - } - if listResp.JSON200 == nil { - return "", apiError(listResp.Status(), listResp.JSON401, listResp.JSON403) - } - if len(listResp.JSON200.Data) == 0 { - return "", fmt.Errorf("no installs found in this workspace") - } - options := make([]prompt.SelectOption, len(listResp.JSON200.Data)) - for i, inst := range listResp.JSON200.Data { - label := inst.Id - if inst.Name != nil { - label = *inst.Name + " (" + inst.Id + ")" - } - options[i] = prompt.SelectOption{Label: label, Value: inst.Id} - } - return prompt.Select("Select an install", options) -} - -func apiError(status string, errs ...*api.Error) error { - for _, e := range errs { - if e != nil { - parts := []string{e.Error.Message} - if e.Error.Suggestion != nil { - parts = append(parts, *e.Error.Suggestion) - } - return fmt.Errorf("%s", strings.Join(parts, ". ")) - } - } - return fmt.Errorf("unexpected response: %s", status) -} - -func deref(s *string) string { - if s == nil { - return "-" - } - return *s -} - -func formatTime(ts float32) string { - return fmt.Sprintf("%.0f", ts) -} diff --git a/internal/cmd/products/products.go b/internal/cmd/products/products.go deleted file mode 100644 index cf4ad24..0000000 --- a/internal/cmd/products/products.go +++ /dev/null @@ -1,239 +0,0 @@ -package products - -import ( - "context" - "fmt" - "strings" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/spf13/cobra" -) - -func NewCmdProducts() *cobra.Command { - cmd := &cobra.Command{ - Use: "products", - Aliases: []string{"product", "prod"}, - Short: "Manage products", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdGet()) - cmd.AddCommand(newCmdDelete()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List products in the active workspace", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - params := &api.GetV1ProductsParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1ProductsWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching products: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - if len(resp.JSON200.Data) == 0 { - fmt.Println("No products found in this workspace.") - return nil - } - - header := []string{"ID", "NAME", "TEMPLATE", "CREATED"} - var rows [][]string - for _, p := range resp.JSON200.Data { - rows = append(rows, []string{p.Id, p.Name, p.TemplateId, formatTime(p.CreatedAt)}) - } - - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdGet() *cobra.Command { - return &cobra.Command{ - Use: "get [product-id]", - Short: "Get product details", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - productID := "" - if len(args) > 0 { - productID = args[0] - } else { - productID, err = pickProduct(cmd.Context(), client) - if err != nil { - return err - } - } - - resp, err := client.GetV1ProductsIdWithResponse(cmd.Context(), productID) - if err != nil { - return fmt.Errorf("fetching product: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - p := resp.JSON200 - - output.PrintTable( - []string{"FIELD", "VALUE"}, - [][]string{ - {"ID", p.Id}, - {"Name", p.Name}, - {"Workspace", p.WorkspaceId}, - {"Template", p.TemplateId}, - }, - ) - return nil - }, - } -} - -func newCmdDelete() *cobra.Command { - var yes bool - - cmd := &cobra.Command{ - Use: "delete [product-id]", - Short: "Delete a product", - Long: "Delete a product. Fails if the product has active installs.", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - productID := "" - if len(args) > 0 { - productID = args[0] - } else { - productID, err = pickProduct(cmd.Context(), client) - if err != nil { - return err - } - } - - if !yes { - if !prompt.IsInteractive() { - return fmt.Errorf("use --yes to confirm deletion in non-interactive mode") - } - confirmed, err := prompt.Confirm(fmt.Sprintf("Delete product %s?", productID)) - if err != nil { - return err - } - if !confirmed { - fmt.Println("Cancelled.") - return nil - } - } - - resp, err := client.DeleteV1ProductsIdWithResponse(cmd.Context(), productID) - if err != nil { - return fmt.Errorf("deleting product: %w", err) - } - if resp.HTTPResponse.StatusCode != 204 { - return apiError(resp.Status(), resp.JSON401, resp.JSON404, resp.JSON409) - } - - fmt.Printf("Product %s deleted.\n", productID) - return nil - }, - } - - cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip confirmation prompt") - - return cmd -} - -// pickProduct shows an interactive product picker. Returns the selected product ID. -func pickProduct(ctx context.Context, client *api.ClientWithResponses) (string, error) { - limit := 100 - listResp, err := client.GetV1ProductsWithResponse(ctx, &api.GetV1ProductsParams{Limit: &limit}) - if err != nil { - return "", fmt.Errorf("fetching products: %w", err) - } - if listResp.JSON200 == nil { - return "", apiError(listResp.Status(), listResp.JSON401, listResp.JSON403) - } - if len(listResp.JSON200.Data) == 0 { - return "", fmt.Errorf("no products found in this workspace") - } - options := make([]prompt.SelectOption, len(listResp.JSON200.Data)) - for i, p := range listResp.JSON200.Data { - options[i] = prompt.SelectOption{Label: p.Name + " (" + p.Id + ")", Value: p.Id} - } - return prompt.Select("Select a product", options) -} - -func apiError(status string, errs ...*api.Error) error { - for _, e := range errs { - if e != nil { - parts := []string{e.Error.Message} - if e.Error.Suggestion != nil { - parts = append(parts, *e.Error.Suggestion) - } - return fmt.Errorf("%s", strings.Join(parts, ". ")) - } - } - return fmt.Errorf("unexpected response: %s", status) -} - -func formatTime(ts float32) string { - return fmt.Sprintf("%.0f", ts) -} diff --git a/internal/cmd/regions/regions.go b/internal/cmd/regions/regions.go deleted file mode 100644 index 6bb94e5..0000000 --- a/internal/cmd/regions/regions.go +++ /dev/null @@ -1,154 +0,0 @@ -package regions - -import ( - "fmt" - "strings" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/spf13/cobra" -) - -func NewCmdRegions() *cobra.Command { - cmd := &cobra.Command{ - Use: "regions", - Aliases: []string{"region", "rg"}, - Short: "Manage regions", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdCreate()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List regions in the active workspace", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - params := &api.GetV1RegionsParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1RegionsWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching regions: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - if len(resp.JSON200.Data) == 0 { - fmt.Println("No regions found in this workspace.") - return nil - } - - header := []string{"ID", "NAME", "ICON"} - var rows [][]string - for _, r := range resp.JSON200.Data { - icon := "-" - if r.Icon != nil { - icon = *r.Icon - } - rows = append(rows, []string{r.Id, r.Name, icon}) - } - - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdCreate() *cobra.Command { - var name, icon string - - cmd := &cobra.Command{ - Use: "create", - Short: "Create a region", - RunE: func(cmd *cobra.Command, args []string) error { - if name == "" { - return fmt.Errorf("--name is required") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - body := api.PostV1RegionsJSONRequestBody{ - Name: name, - } - if icon != "" { - body.Icon = &icon - } - - resp, err := client.PostV1RegionsWithResponse(cmd.Context(), body) - if err != nil { - return fmt.Errorf("creating region: %w", err) - } - if resp.JSON201 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403, resp.JSON422) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON201) - } - - fmt.Printf("Region %s created (%s).\n", resp.JSON201.Name, resp.JSON201.Id) - return nil - }, - } - - cmd.Flags().StringVar(&name, "name", "", "Region name (required)") - cmd.Flags().StringVar(&icon, "icon", "", "Icon URL") - _ = cmd.MarkFlagRequired("name") - - return cmd -} - -func apiError(status string, errs ...*api.Error) error { - for _, e := range errs { - if e != nil { - parts := []string{e.Error.Message} - if e.Error.Suggestion != nil { - parts = append(parts, *e.Error.Suggestion) - } - return fmt.Errorf("%s", strings.Join(parts, ". ")) - } - } - return fmt.Errorf("unexpected response: %s", status) -} diff --git a/internal/cmd/registry/registry.go b/internal/cmd/registry/registry.go deleted file mode 100644 index fbe6fa2..0000000 --- a/internal/cmd/registry/registry.go +++ /dev/null @@ -1,183 +0,0 @@ -package registry - -import ( - "context" - "fmt" - "strings" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/spf13/cobra" -) - -func NewCmdRegistry() *cobra.Command { - cmd := &cobra.Command{ - Use: "registry", - Aliases: []string{"reg"}, - Short: "Manage registry credentials", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdDelete()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List registry credentials in the active workspace", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - params := &api.GetV1RegistryCredentialsParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1RegistryCredentialsWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching registry credentials: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - if len(resp.JSON200.Data) == 0 { - fmt.Println("No registry credentials found in this workspace.") - return nil - } - - header := []string{"ID", "NAME", "REGISTRY", "TYPE", "ACTIVE"} - var rows [][]string - for _, c := range resp.JSON200.Data { - active := "yes" - if !c.IsActive { - active = "no" - } - rows = append(rows, []string{c.Id, c.Name, c.RegistryUrl, string(c.Type), active}) - } - - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdDelete() *cobra.Command { - var yes bool - - cmd := &cobra.Command{ - Use: "delete [credential-id]", - Short: "Delete a registry credential", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - credentialID := "" - if len(args) > 0 { - credentialID = args[0] - } else { - credentialID, err = pickCredential(cmd.Context(), client) - if err != nil { - return err - } - } - - if !yes { - if !prompt.IsInteractive() { - return fmt.Errorf("use --yes to confirm deletion in non-interactive mode") - } - confirmed, err := prompt.Confirm(fmt.Sprintf("Delete registry credential %s?", credentialID)) - if err != nil { - return err - } - if !confirmed { - fmt.Println("Cancelled.") - return nil - } - } - - resp, err := client.DeleteV1RegistryCredentialsIdWithResponse(cmd.Context(), credentialID) - if err != nil { - return fmt.Errorf("deleting credential: %w", err) - } - if resp.HTTPResponse.StatusCode != 204 { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - fmt.Printf("Registry credential %s deleted.\n", credentialID) - return nil - }, - } - - cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip confirmation prompt") - - return cmd -} - -// pickCredential shows an interactive registry credential picker. Returns the selected credential ID. -func pickCredential(ctx context.Context, client *api.ClientWithResponses) (string, error) { - limit := 100 - listResp, err := client.GetV1RegistryCredentialsWithResponse(ctx, &api.GetV1RegistryCredentialsParams{Limit: &limit}) - if err != nil { - return "", fmt.Errorf("fetching registry credentials: %w", err) - } - if listResp.JSON200 == nil { - return "", apiError(listResp.Status(), listResp.JSON401, listResp.JSON403) - } - if len(listResp.JSON200.Data) == 0 { - return "", fmt.Errorf("no registry credentials found in this workspace") - } - options := make([]prompt.SelectOption, len(listResp.JSON200.Data)) - for i, c := range listResp.JSON200.Data { - options[i] = prompt.SelectOption{Label: c.Name + " (" + c.RegistryUrl + ")", Value: c.Id} - } - return prompt.Select("Select a credential", options) -} - -func apiError(status string, errs ...*api.Error) error { - for _, e := range errs { - if e != nil { - parts := []string{e.Error.Message} - if e.Error.Suggestion != nil { - parts = append(parts, *e.Error.Suggestion) - } - return fmt.Errorf("%s", strings.Join(parts, ". ")) - } - } - return fmt.Errorf("unexpected response: %s", status) -} diff --git a/internal/cmd/root.go b/internal/cmd/root.go deleted file mode 100644 index d22de60..0000000 --- a/internal/cmd/root.go +++ /dev/null @@ -1,102 +0,0 @@ -package cmd - -import ( - "context" - "fmt" - "os" - "strings" - "time" - - authcmd "github.com/cnap-tech/cli/internal/cmd/auth" - clusterscmd "github.com/cnap-tech/cli/internal/cmd/clusters" - installscmd "github.com/cnap-tech/cli/internal/cmd/installs" - productscmd "github.com/cnap-tech/cli/internal/cmd/products" - regionscmd "github.com/cnap-tech/cli/internal/cmd/regions" - registrycmd "github.com/cnap-tech/cli/internal/cmd/registry" - templatescmd "github.com/cnap-tech/cli/internal/cmd/templates" - workspacescmd "github.com/cnap-tech/cli/internal/cmd/workspaces" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/debug" - "github.com/cnap-tech/cli/internal/update" - "github.com/cnap-tech/cli/internal/useragent" - "github.com/spf13/cobra" -) - -var ( - version = "dev" - commit = "none" -) - -func Execute(ctx context.Context) error { - root := rootCmd() - - // Background update check (gh CLI pattern) - updateCh := make(chan *update.ReleaseInfo) - go func() { - if version == "dev" || !update.ShouldCheckForUpdate() { - updateCh <- nil - return - } - checkCtx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - rel, _ := update.CheckForUpdate(checkCtx, version) - updateCh <- rel - }() - - err := root.ExecuteContext(ctx) - - // Print update notice after command output - if newRelease := <-updateCh; newRelease != nil { - isHomebrew := update.IsUnderHomebrew() - if !isHomebrew || !update.IsRecentRelease(newRelease.PublishedAt) { - fmt.Fprintf(os.Stderr, "\nA new release of cnap is available: %s → %s\n", - strings.TrimPrefix(version, "v"), - strings.TrimPrefix(newRelease.Version, "v")) - if isHomebrew { - fmt.Fprintf(os.Stderr, "To upgrade, run: brew upgrade cnap\n") - } - fmt.Fprintf(os.Stderr, "%s\n", newRelease.URL) - } - } - - return err -} - -func rootCmd() *cobra.Command { - useragent.SetVersion(version) - - var debugFlag bool - - root := &cobra.Command{ - Use: "cnap", - Short: "CNAP CLI — manage workspaces, clusters, and deployments", - Long: `CNAP CLI provides programmatic access to your CNAP workspace. - -Manage clusters, templates, products, and deployments from the terminal. -Authenticate with a Personal Access Token or via browser login.`, - SilenceUsage: true, - SilenceErrors: true, - Version: fmt.Sprintf("%s (%s)", version, commit), - PersistentPreRun: func(cmd *cobra.Command, args []string) { - debug.Init(debugFlag) - if debug.Enabled { - debug.Install() - } - }, - } - - root.PersistentFlags().BoolVar(&debugFlag, "debug", false, "Enable debug logging (or set CNAP_DEBUG=1)") - root.PersistentFlags().StringVarP(&cmdutil.OutputFormat, "output", "o", "", "Output format: table, json, quiet") - root.PersistentFlags().StringVar(&cmdutil.APIURL, "api-url", "", "API base URL (overrides config)") - - root.AddCommand(authcmd.NewCmdAuth()) - root.AddCommand(workspacescmd.NewCmdWorkspaces()) - root.AddCommand(clusterscmd.NewCmdClusters()) - root.AddCommand(templatescmd.NewCmdTemplates()) - root.AddCommand(productscmd.NewCmdProducts()) - root.AddCommand(installscmd.NewCmdInstalls()) - root.AddCommand(regionscmd.NewCmdRegions()) - root.AddCommand(registrycmd.NewCmdRegistry()) - - return root -} diff --git a/internal/cmd/templates/templates.go b/internal/cmd/templates/templates.go deleted file mode 100644 index 3bf4057..0000000 --- a/internal/cmd/templates/templates.go +++ /dev/null @@ -1,269 +0,0 @@ -package templates - -import ( - "context" - "fmt" - "strings" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/spf13/cobra" -) - -func NewCmdTemplates() *cobra.Command { - cmd := &cobra.Command{ - Use: "templates", - Aliases: []string{"template", "tpl"}, - Short: "Manage templates", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdGet()) - cmd.AddCommand(newCmdDelete()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List templates in the active workspace", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - if cfg.ActiveWorkspace == "" { - return fmt.Errorf("no active workspace. Run: cnap workspaces switch ") - } - - params := &api.GetV1TemplatesParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1TemplatesWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching templates: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON403) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - if len(resp.JSON200.Data) == 0 { - fmt.Println("No templates found in this workspace.") - return nil - } - - header := []string{"ID", "NAME", "PROXY MODE", "CREATED"} - var rows [][]string - for _, t := range resp.JSON200.Data { - proxyMode := "-" - if t.RegistryProxyMode != nil { - proxyMode = string(*t.RegistryProxyMode) - } - rows = append(rows, []string{t.Id, t.Name, proxyMode, formatTime(t.CreatedAt)}) - } - - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdGet() *cobra.Command { - return &cobra.Command{ - Use: "get [template-id]", - Short: "Get template details with helm sources", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - templateID := "" - if len(args) > 0 { - templateID = args[0] - } else { - templateID, err = pickTemplate(cmd.Context(), client) - if err != nil { - return err - } - } - - resp, err := client.GetV1TemplatesIdWithResponse(cmd.Context(), templateID) - if err != nil { - return fmt.Errorf("fetching template: %w", err) - } - if resp.JSON200 == nil { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - t := resp.JSON200 - proxyMode := "-" - if t.RegistryProxyMode != nil { - proxyMode = string(*t.RegistryProxyMode) - } - - output.PrintTable( - []string{"FIELD", "VALUE"}, - [][]string{ - {"ID", t.Id}, - {"Name", t.Name}, - {"Workspace", t.WorkspaceId}, - {"Registry Proxy", proxyMode}, - {"Sources", fmt.Sprintf("%d helm source(s)", len(t.HelmSources))}, - }, - ) - - if len(t.HelmSources) > 0 { - fmt.Println() - header := []string{"SOURCE ID", "REPO URL", "CHART", "VERSION"} - var rows [][]string - for _, s := range t.HelmSources { - chart := deref(s.Chart.Chart) - if chart == "" && s.Chart.Path != nil { - chart = *s.Chart.Path - } - rows = append(rows, []string{s.Id, s.Chart.RepoUrl, chart, s.Chart.TargetRevision}) - } - output.PrintTable(header, rows) - } - - return nil - }, - } -} - -func newCmdDelete() *cobra.Command { - var yes bool - - cmd := &cobra.Command{ - Use: "delete [template-id]", - Short: "Delete a template", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, _, err := cmdutil.NewClient() - if err != nil { - return err - } - - templateID := "" - if len(args) > 0 { - templateID = args[0] - } else { - templateID, err = pickTemplate(cmd.Context(), client) - if err != nil { - return err - } - } - - if !yes { - if !prompt.IsInteractive() { - return fmt.Errorf("use --yes to confirm deletion in non-interactive mode") - } - confirmed, err := prompt.Confirm(fmt.Sprintf("Delete template %s?", templateID)) - if err != nil { - return err - } - if !confirmed { - fmt.Println("Cancelled.") - return nil - } - } - - resp, err := client.DeleteV1TemplatesIdWithResponse(cmd.Context(), templateID) - if err != nil { - return fmt.Errorf("deleting template: %w", err) - } - if resp.HTTPResponse.StatusCode != 204 { - return apiError(resp.Status(), resp.JSON401, resp.JSON404) - } - - fmt.Printf("Template %s deleted.\n", templateID) - return nil - }, - } - - cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip confirmation prompt") - - return cmd -} - -// pickTemplate shows an interactive template picker. Returns the selected template ID. -func pickTemplate(ctx context.Context, client *api.ClientWithResponses) (string, error) { - limit := 100 - listResp, err := client.GetV1TemplatesWithResponse(ctx, &api.GetV1TemplatesParams{Limit: &limit}) - if err != nil { - return "", fmt.Errorf("fetching templates: %w", err) - } - if listResp.JSON200 == nil { - return "", apiError(listResp.Status(), listResp.JSON401, listResp.JSON403) - } - if len(listResp.JSON200.Data) == 0 { - return "", fmt.Errorf("no templates found in this workspace") - } - options := make([]prompt.SelectOption, len(listResp.JSON200.Data)) - for i, t := range listResp.JSON200.Data { - options[i] = prompt.SelectOption{Label: t.Name + " (" + t.Id + ")", Value: t.Id} - } - return prompt.Select("Select a template", options) -} - -func apiError(status string, errs ...*api.Error) error { - for _, e := range errs { - if e != nil { - parts := []string{e.Error.Message} - if e.Error.Suggestion != nil { - parts = append(parts, *e.Error.Suggestion) - } - return fmt.Errorf("%s", strings.Join(parts, ". ")) - } - } - return fmt.Errorf("unexpected response: %s", status) -} - -func deref(s *string) string { - if s == nil { - return "-" - } - return *s -} - -func formatTime(ts float32) string { - return fmt.Sprintf("%.0f", ts) -} diff --git a/internal/cmd/workspaces/workspaces.go b/internal/cmd/workspaces/workspaces.go deleted file mode 100644 index dd5fa57..0000000 --- a/internal/cmd/workspaces/workspaces.go +++ /dev/null @@ -1,154 +0,0 @@ -package workspaces - -import ( - "fmt" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/cmdutil" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/prompt" - "github.com/spf13/cobra" -) - -func NewCmdWorkspaces() *cobra.Command { - cmd := &cobra.Command{ - Use: "workspaces", - Aliases: []string{"workspace", "ws"}, - Short: "Manage workspaces", - } - - cmd.AddCommand(newCmdList()) - cmd.AddCommand(newCmdSwitch()) - - return cmd -} - -func newCmdList() *cobra.Command { - var limit int - var cursor string - - cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "List your workspaces", - RunE: func(cmd *cobra.Command, args []string) error { - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - params := &api.GetV1WorkspacesParams{Limit: &limit} - if cursor != "" { - params.Cursor = &cursor - } - - resp, err := client.GetV1WorkspacesWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching workspaces: %w", err) - } - if resp.JSON200 == nil { - return fmt.Errorf("unexpected response: %s", resp.Status()) - } - - format := cmdutil.GetOutputFormat(cfg) - if format == output.FormatJSON { - return output.PrintJSON(resp.JSON200) - } - - header := []string{"ID", "NAME"} - var rows [][]string - for _, w := range resp.JSON200.Data { - active := "" - if w.Id == cfg.ActiveWorkspace { - active = " (active)" - } - rows = append(rows, []string{w.Id, w.Name + active}) - } - output.PrintTable(header, rows) - if resp.JSON200.Pagination.HasMore { - fmt.Printf("\nMore results available. Use --cursor %s to see next page.\n", *resp.JSON200.Pagination.Cursor) - } - return nil - }, - } - - cmd.Flags().IntVar(&limit, "limit", 50, "Items per page (1-100)") - cmd.Flags().StringVar(&cursor, "cursor", "", "Pagination cursor from previous response") - - return cmd -} - -func newCmdSwitch() *cobra.Command { - return &cobra.Command{ - Use: "switch [workspace-id]", - Short: "Set the active workspace", - Long: `Set the active workspace for subsequent commands. - -When run interactively without arguments, shows a picker to select a workspace. -In non-interactive environments (CI, pipes), the workspace ID argument is required.`, - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - // Fail fast in non-interactive mode without an argument - if len(args) == 0 && !prompt.IsInteractive() { - return fmt.Errorf(" argument required when not running interactively") - } - - client, cfg, err := cmdutil.NewClient() - if err != nil { - return err - } - - var workspaceID string - - if len(args) > 0 { - // Validate the workspace ID by fetching it - workspaceID = args[0] - resp, err := client.GetV1WorkspacesIdWithResponse(cmd.Context(), workspaceID) - if err != nil { - return fmt.Errorf("validating workspace: %w", err) - } - if resp.JSON200 == nil { - return fmt.Errorf("workspace %q not found", workspaceID) - } - fmt.Printf("Workspace: %s\n", resp.JSON200.Name) - } else { - // Fetch workspaces for interactive selection - limit := 100 - params := &api.GetV1WorkspacesParams{Limit: &limit} - resp, err := client.GetV1WorkspacesWithResponse(cmd.Context(), params) - if err != nil { - return fmt.Errorf("fetching workspaces: %w", err) - } - if resp.JSON200 == nil { - return fmt.Errorf("unexpected response: %s", resp.Status()) - } - - if len(resp.JSON200.Data) == 0 { - return fmt.Errorf("no workspaces found") - } - - options := make([]prompt.SelectOption, len(resp.JSON200.Data)) - for i, w := range resp.JSON200.Data { - label := w.Name - if w.Id == cfg.ActiveWorkspace { - label += " (active)" - } - options[i] = prompt.SelectOption{Label: label, Value: w.Id} - } - - workspaceID, err = prompt.Select("Select a workspace", options) - if err != nil { - return err - } - } - - cfg.ActiveWorkspace = workspaceID - if err := cfg.Save(); err != nil { - return fmt.Errorf("saving config: %w", err) - } - - fmt.Printf("Active workspace set to: %s\n", workspaceID) - return nil - }, - } -} diff --git a/internal/cmdutil/client.go b/internal/cmdutil/client.go deleted file mode 100644 index b9b1802..0000000 --- a/internal/cmdutil/client.go +++ /dev/null @@ -1,68 +0,0 @@ -package cmdutil - -import ( - "context" - "fmt" - "log/slog" - "net/http" - - "github.com/cnap-tech/cli/internal/api" - "github.com/cnap-tech/cli/internal/config" - "github.com/cnap-tech/cli/internal/debug" - "github.com/cnap-tech/cli/internal/output" - "github.com/cnap-tech/cli/internal/useragent" -) - -// OutputFormat holds the CLI-level --output flag value. -// Set by the root command's PersistentFlags. -var OutputFormat string - -// APIURL holds the CLI-level --api-url flag value. -var APIURL string - -// NewClient creates an authenticated API client from config. -func NewClient() (*api.ClientWithResponses, *config.Config, error) { - cfg, err := config.Load() - if err != nil { - return nil, nil, fmt.Errorf("loading config: %w", err) - } - - if APIURL != "" { - cfg.APIURL = APIURL - } - - token := cfg.Token() - if token == "" { - return nil, nil, fmt.Errorf("not authenticated. Run: cnap auth login") - } - - baseURL := cfg.BaseURL() - slog.Debug("creating API client", "base_url", baseURL, "workspace", cfg.ActiveWorkspace, "user_agent", useragent.String()) - - client, err := api.NewClientWithResponses(baseURL, api.WithHTTPClient(debug.Client()), api.WithRequestEditorFn( - func(_ context.Context, req *http.Request) error { - req.Header.Set("Authorization", "Bearer "+token) - req.Header.Set("User-Agent", useragent.String()) - if cfg.ActiveWorkspace != "" { - req.Header.Set("X-Workspace-Id", cfg.ActiveWorkspace) - } - return nil - }, - )) - if err != nil { - return nil, nil, fmt.Errorf("creating API client: %w", err) - } - - return client, cfg, nil -} - -// GetOutputFormat returns the effective output format. -func GetOutputFormat(cfg *config.Config) output.Format { - if OutputFormat != "" { - return output.Format(OutputFormat) - } - if cfg.Output.Format != "" { - return output.Format(cfg.Output.Format) - } - return output.FormatTable -} diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100644 index 973a520..0000000 --- a/internal/config/config.go +++ /dev/null @@ -1,124 +0,0 @@ -package config - -import ( - "fmt" - "os" - "path/filepath" - - "gopkg.in/yaml.v3" -) - -const ( - DefaultAPIURL = "https://api.cnap.tech" - DefaultAuthURL = "https://cnap.tech" - configDir = ".cnap" - configFile = "config.yaml" -) - -type Config struct { - APIURL string `yaml:"api_url"` - AuthURL string `yaml:"auth_url,omitempty"` - ActiveWorkspace string `yaml:"active_workspace,omitempty"` - Auth Auth `yaml:"auth"` - Output Output `yaml:"output"` -} - -type Auth struct { - Token string `yaml:"token,omitempty"` -} - -type Output struct { - Format string `yaml:"format"` // table, json, quiet -} - -func DefaultConfig() *Config { - return &Config{ - APIURL: DefaultAPIURL, - Output: Output{Format: "table"}, - } -} - -func configPath() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("cannot find home directory: %w", err) - } - return filepath.Join(home, configDir, configFile), nil -} - -func ConfigDir() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("cannot find home directory: %w", err) - } - return filepath.Join(home, configDir), nil -} - -func Load() (*Config, error) { - path, err := configPath() - if err != nil { - return DefaultConfig(), nil //nolint:nilerr // no home dir → use defaults - } - - data, err := os.ReadFile(path) - if err != nil { - if os.IsNotExist(err) { - return DefaultConfig(), nil - } - return nil, fmt.Errorf("reading config: %w", err) - } - - cfg := DefaultConfig() - if err := yaml.Unmarshal(data, cfg); err != nil { - return nil, fmt.Errorf("parsing config: %w", err) - } - return cfg, nil -} - -func (c *Config) Save() error { - path, err := configPath() - if err != nil { - return err - } - - if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { - return fmt.Errorf("creating config directory: %w", err) - } - - data, err := yaml.Marshal(c) - if err != nil { - return fmt.Errorf("marshaling config: %w", err) - } - - return os.WriteFile(path, data, 0o600) -} - -// Token returns the API token from env var or config file. -// Env var CNAP_API_TOKEN takes priority. -func (c *Config) Token() string { - if t := os.Getenv("CNAP_API_TOKEN"); t != "" { - return t - } - return c.Auth.Token -} - -// BaseURL returns the API base URL from env var or config file. -// Env var CNAP_API_URL takes priority. -func (c *Config) BaseURL() string { - if u := os.Getenv("CNAP_API_URL"); u != "" { - return u - } - return c.APIURL -} - -// AuthBaseURL returns the auth/dashboard base URL from env var or config file. -// Env var CNAP_AUTH_URL takes priority. Used for device flow auth endpoints. -func (c *Config) AuthBaseURL() string { - if u := os.Getenv("CNAP_AUTH_URL"); u != "" { - return u - } - if c.AuthURL != "" { - return c.AuthURL - } - return DefaultAuthURL -} diff --git a/internal/debug/debug.go b/internal/debug/debug.go deleted file mode 100644 index 130fda3..0000000 --- a/internal/debug/debug.go +++ /dev/null @@ -1,31 +0,0 @@ -// Package debug configures structured logging for the CLI. -// -// When --debug or CNAP_DEBUG=1 is set, debug-level logs are emitted to stderr. -// Otherwise, only warn and above are shown (effectively silent). -package debug - -import ( - "io" - "log/slog" - "os" -) - -// Enabled reports whether debug mode is active. -var Enabled bool - -// Init configures the global slog logger. -// Call once from the root command's PersistentPreRun. -func Init(flagEnabled bool) { - Enabled = flagEnabled || os.Getenv("CNAP_DEBUG") != "" - - w := io.Discard - level := slog.LevelWarn - if Enabled { - w = os.Stderr - level = slog.LevelDebug - } - - slog.SetDefault(slog.New(slog.NewTextHandler(w, &slog.HandlerOptions{ - Level: level, - }))) -} diff --git a/internal/debug/transport.go b/internal/debug/transport.go deleted file mode 100644 index 90fceec..0000000 --- a/internal/debug/transport.go +++ /dev/null @@ -1,64 +0,0 @@ -package debug - -import ( - "log/slog" - "net/http" - "time" -) - -// Transport wraps an http.RoundTripper and logs request/response details -// when debug mode is enabled. -type Transport struct { - Inner http.RoundTripper -} - -func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { - if !Enabled { - return t.inner().RoundTrip(req) - } - - slog.Debug("HTTP request", - "method", req.Method, - "url", req.URL.String(), - ) - - start := time.Now() - resp, err := t.inner().RoundTrip(req) - elapsed := time.Since(start) - - if err != nil { - slog.Debug("HTTP error", "method", req.Method, "url", req.URL.String(), "error", err, "duration", elapsed) - return nil, err - } - - slog.Debug("HTTP response", - "method", req.Method, - "url", req.URL.String(), - "status", resp.StatusCode, - "duration", elapsed, - ) - - return resp, nil -} - -func (t *Transport) inner() http.RoundTripper { - if t.Inner != nil { - return t.Inner - } - return http.DefaultTransport -} - -// Install replaces http.DefaultClient's transport with a debug-logging wrapper. -// This covers manual http.DefaultClient.Do() calls (e.g. device flow). -func Install() { - http.DefaultClient.Transport = &Transport{Inner: http.DefaultClient.Transport} -} - -// Client returns an *http.Client with the debug transport. -// Use this when a library creates its own http.Client (e.g. oapi-codegen). -func Client() *http.Client { - if !Enabled { - return http.DefaultClient - } - return &http.Client{Transport: &Transport{Inner: http.DefaultTransport}} -} diff --git a/internal/output/output.go b/internal/output/output.go deleted file mode 100644 index 1dc3ace..0000000 --- a/internal/output/output.go +++ /dev/null @@ -1,53 +0,0 @@ -package output - -import ( - "encoding/json" - "fmt" - "io" - "os" - "text/tabwriter" -) - -// Format controls output mode. -type Format string - -const ( - FormatTable Format = "table" - FormatJSON Format = "json" - FormatQuiet Format = "quiet" -) - -// PrintJSON writes v as indented JSON to stdout. -func PrintJSON(v any) error { - enc := json.NewEncoder(os.Stdout) - enc.SetIndent("", " ") - return enc.Encode(v) -} - -// Table creates a tab writer for aligned columns. -func Table(w io.Writer) *tabwriter.Writer { - return tabwriter.NewWriter(w, 0, 0, 2, ' ', 0) -} - -// PrintTable prints rows with a header using tabwriter. -func PrintTable(header []string, rows [][]string) { - tw := Table(os.Stdout) - for i, h := range header { - if i > 0 { - _, _ = fmt.Fprint(tw, "\t") - } - _, _ = fmt.Fprint(tw, h) - } - _, _ = fmt.Fprintln(tw) - - for _, row := range rows { - for i, col := range row { - if i > 0 { - _, _ = fmt.Fprint(tw, "\t") - } - _, _ = fmt.Fprint(tw, col) - } - _, _ = fmt.Fprintln(tw) - } - _ = tw.Flush() -} diff --git a/internal/prompt/prompt.go b/internal/prompt/prompt.go deleted file mode 100644 index 660fbdd..0000000 --- a/internal/prompt/prompt.go +++ /dev/null @@ -1,77 +0,0 @@ -// Package prompt provides interactive terminal prompts with TTY detection. -// -// When stdin is a TTY (interactive terminal), prompts are shown using huh. -// When stdin is not a TTY (CI, piped input), prompts return an error -// so the caller can require explicit flags/arguments instead. -package prompt - -import ( - "fmt" - "os" - - "github.com/charmbracelet/huh" - "golang.org/x/term" -) - -// IsInteractive reports whether stdin is a terminal. -func IsInteractive() bool { - return term.IsTerminal(int(os.Stdin.Fd())) -} - -// ErrNonInteractive is returned when a prompt is attempted without a TTY. -var ErrNonInteractive = fmt.Errorf("required argument missing (not running interactively)") - -// SelectOption is a single item in a select prompt. -type SelectOption struct { - Label string - Value string -} - -// Select shows an interactive select list and returns the chosen value. -// Returns ErrNonInteractive if stdin is not a TTY. -func Select(title string, options []SelectOption) (string, error) { - if !IsInteractive() { - return "", ErrNonInteractive - } - - huhOpts := make([]huh.Option[string], len(options)) - for i, o := range options { - huhOpts[i] = huh.NewOption(o.Label, o.Value) - } - - var selected string - err := huh.NewSelect[string](). - Title(title). - Options(huhOpts...). - Value(&selected). - WithTheme(ThemeCNAP()). - Run() - if err != nil { - return "", err - } - - return selected, nil -} - -// Confirm shows a yes/no confirmation prompt with the given message. -// Returns true if the user confirmed, false if they declined. -// Returns ErrNonInteractive if stdin is not a TTY. -func Confirm(message string) (bool, error) { - if !IsInteractive() { - return false, ErrNonInteractive - } - - var confirmed bool - err := huh.NewConfirm(). - Title(message). - Affirmative("Yes"). - Negative("No"). - Value(&confirmed). - WithTheme(ThemeCNAP()). - Run() - if err != nil { - return false, err - } - - return confirmed, nil -} diff --git a/internal/prompt/theme.go b/internal/prompt/theme.go deleted file mode 100644 index 5fadd72..0000000 --- a/internal/prompt/theme.go +++ /dev/null @@ -1,80 +0,0 @@ -package prompt - -import ( - "github.com/charmbracelet/huh" - "github.com/charmbracelet/lipgloss" -) - -// ThemeCNAP returns a huh theme matching CNAP's brand identity. -// -// Design: borderless, minimal, with CNAP red as a subtle accent on the -// selector arrow only. The highlighted option is bold+bright while -// non-highlighted options recede into dim gray. This avoids the -// "error/danger" feel that saturated red text creates in terminals. -func ThemeCNAP() *huh.Theme { - t := huh.ThemeBase() - - var ( - normalFg = lipgloss.AdaptiveColor{Light: "235", Dark: "252"} - brightFg = lipgloss.AdaptiveColor{Light: "232", Dark: "255"} - dimFg = lipgloss.AdaptiveColor{Light: "245", Dark: "243"} - subtleFg = lipgloss.AdaptiveColor{Light: "250", Dark: "238"} - - // Moderated CNAP red — warm and recognizable without screaming "error". - accent = lipgloss.AdaptiveColor{Light: "#C04040", Dark: "#D85555"} - green = lipgloss.AdaptiveColor{Light: "#2A7A45", Dark: "#3DA060"} - ) - - // --- Focused state --- - f := &t.Focused - - // Borderless: no left border, just padding for clean alignment. - f.Base = lipgloss.NewStyle().PaddingLeft(1) - f.Card = f.Base - f.Title = f.Title.Foreground(normalFg).Bold(true) - f.NoteTitle = f.NoteTitle.Foreground(normalFg).Bold(true).MarginBottom(1) - f.Description = f.Description.Foreground(dimFg) - f.ErrorIndicator = f.ErrorIndicator.Foreground(accent) - f.ErrorMessage = f.ErrorMessage.Foreground(accent) - - // Select: ▸ selector in accent, highlighted item bold+bright, rest dim. - f.SelectSelector = lipgloss.NewStyle().SetString("▸ ").Foreground(accent) - f.SelectedOption = f.SelectedOption.Foreground(brightFg).Bold(true) - f.UnselectedOption = f.UnselectedOption.Foreground(dimFg) - f.Option = f.Option.Foreground(normalFg) - f.NextIndicator = f.NextIndicator.Foreground(subtleFg) - f.PrevIndicator = f.PrevIndicator.Foreground(subtleFg) - - // Multi-select: ● / ○ with accent + green. - f.MultiSelectSelector = lipgloss.NewStyle().SetString("▸ ").Foreground(accent) - f.SelectedOption = f.SelectedOption.Foreground(brightFg).Bold(true) - f.SelectedPrefix = lipgloss.NewStyle().Foreground(green).SetString("● ") - f.UnselectedPrefix = lipgloss.NewStyle().Foreground(dimFg).SetString("○ ") - f.UnselectedOption = f.UnselectedOption.Foreground(dimFg) - - // Buttons. - f.FocusedButton = f.FocusedButton.Foreground(lipgloss.Color("255")).Background(accent) - f.Next = f.FocusedButton - f.BlurredButton = f.BlurredButton.Foreground(normalFg).Background(lipgloss.AdaptiveColor{Light: "254", Dark: "236"}) - - // File picker. - f.Directory = f.Directory.Foreground(accent) - - // Text input. - f.TextInput.Cursor = f.TextInput.Cursor.Foreground(accent) - f.TextInput.Placeholder = f.TextInput.Placeholder.Foreground(lipgloss.AdaptiveColor{Light: "248", Dark: "238"}) - f.TextInput.Prompt = f.TextInput.Prompt.Foreground(accent) - - // --- Blurred state: same styles, no border --- - t.Blurred = *f - t.Blurred.Base = lipgloss.NewStyle().PaddingLeft(1) - t.Blurred.Card = t.Blurred.Base - t.Blurred.NextIndicator = lipgloss.NewStyle() - t.Blurred.PrevIndicator = lipgloss.NewStyle() - - // --- Group --- - t.Group.Title = f.Title - t.Group.Description = f.Description - - return t -} diff --git a/internal/update/update.go b/internal/update/update.go deleted file mode 100644 index 17909ac..0000000 --- a/internal/update/update.go +++ /dev/null @@ -1,211 +0,0 @@ -// Package update provides version update checking for the CNAP CLI. -// It checks the GitHub Releases API in the background and caches results -// for 24 hours to avoid excessive API calls. -package update - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/cnap-tech/cli/internal/config" - "golang.org/x/term" - "gopkg.in/yaml.v3" -) - -const ( - repo = "cnap-tech/cli" - stateFile = "state.yaml" -) - -// ReleaseInfo stores information about a GitHub release. -type ReleaseInfo struct { - Version string `json:"tag_name"` - URL string `json:"html_url"` - PublishedAt time.Time `json:"published_at"` -} - -type stateEntry struct { - CheckedForUpdateAt time.Time `yaml:"checked_for_update_at"` - LatestRelease ReleaseInfo `yaml:"latest_release"` -} - -// ShouldCheckForUpdate returns true if the environment is suitable for update checks. -func ShouldCheckForUpdate() bool { - if os.Getenv("CNAP_NO_UPDATE_NOTIFIER") != "" { - return false - } - if os.Getenv("CODESPACES") != "" { - return false - } - if isCI() { - return false - } - return term.IsTerminal(int(os.Stderr.Fd())) -} - -// CheckForUpdate checks whether a newer version of the CLI is available. -// Returns nil if the check was performed recently (within 24h) or if the -// current version is up to date. -func CheckForUpdate(ctx context.Context, currentVersion string) (*ReleaseInfo, error) { - stateFilePath, err := statePath() - if err != nil { - return nil, err - } - - // Return early if checked recently - state, _ := getState(stateFilePath) - if state != nil && time.Since(state.CheckedForUpdateAt).Hours() < 24 { - return nil, nil - } - - // Fetch latest release from GitHub - release, err := fetchLatestRelease(ctx) - if err != nil { - return nil, err - } - - // Cache the result - _ = setState(stateFilePath, time.Now(), *release) - - if versionGreaterThan(release.Version, currentVersion) { - return release, nil - } - - return nil, nil -} - -// IsUnderHomebrew returns true if the CLI binary is managed by Homebrew. -func IsUnderHomebrew() bool { - exe, err := os.Executable() - if err != nil { - return false - } - - brewExe, err := exec.LookPath("brew") - if err != nil { - return false - } - - brewPrefixBytes, err := exec.Command(brewExe, "--prefix").Output() - if err != nil { - return false - } - - brewBinPrefix := filepath.Join(strings.TrimSpace(string(brewPrefixBytes)), "bin") + string(filepath.Separator) - return strings.HasPrefix(exe, brewBinPrefix) -} - -// IsRecentRelease returns true if the release was published less than 24 hours ago. -func IsRecentRelease(publishedAt time.Time) bool { - return !publishedAt.IsZero() && time.Since(publishedAt) < 24*time.Hour -} - -func statePath() (string, error) { - dir, err := config.ConfigDir() - if err != nil { - return "", err - } - return filepath.Join(dir, stateFile), nil -} - -func getState(path string) (*stateEntry, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - var s stateEntry - if err := yaml.Unmarshal(data, &s); err != nil { - return nil, err - } - return &s, nil -} - -func setState(path string, t time.Time, r ReleaseInfo) error { - data, err := yaml.Marshal(stateEntry{CheckedForUpdateAt: t, LatestRelease: r}) - if err != nil { - return err - } - if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { - return err - } - return os.WriteFile(path, data, 0o600) -} - -func fetchLatestRelease(ctx context.Context) (*ReleaseInfo, error) { - url := fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", repo) - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) - if err != nil { - return nil, err - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - defer func() { - _, _ = io.Copy(io.Discard, resp.Body) - _ = resp.Body.Close() - }() - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("unexpected HTTP %d", resp.StatusCode) - } - - var release ReleaseInfo - if err := json.NewDecoder(resp.Body).Decode(&release); err != nil { - return nil, err - } - return &release, nil -} - -// versionGreaterThan returns true if v is a newer version than w. -// Versions are expected as semver strings with optional "v" prefix (e.g. "v0.5.1" or "0.5.1"). -func versionGreaterThan(v, w string) bool { - vParts := parseVersion(v) - wParts := parseVersion(w) - if vParts == nil || wParts == nil { - return false - } - for i := 0; i < 3; i++ { - if vParts[i] > wParts[i] { - return true - } - if vParts[i] < wParts[i] { - return false - } - } - return false -} - -func parseVersion(s string) []int { - s = strings.TrimPrefix(s, "v") - parts := strings.SplitN(s, ".", 3) - if len(parts) != 3 { - return nil - } - nums := make([]int, 3) - for i, p := range parts { - n, err := strconv.Atoi(p) - if err != nil { - return nil - } - nums[i] = n - } - return nums -} - -// isCI returns true if running in a known CI environment. -func isCI() bool { - return os.Getenv("CI") != "" || - os.Getenv("BUILD_NUMBER") != "" || - os.Getenv("RUN_ID") != "" -} diff --git a/internal/update/update_test.go b/internal/update/update_test.go deleted file mode 100644 index 3937b52..0000000 --- a/internal/update/update_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package update - -import "testing" - -func TestVersionGreaterThan(t *testing.T) { - tests := []struct { - v, w string - want bool - }{ - {"v0.5.1", "v0.5.0", true}, - {"0.5.1", "0.5.0", true}, - {"v0.5.0", "v0.5.0", false}, - {"v0.4.0", "v0.5.0", false}, - {"v1.0.0", "v0.9.9", true}, - {"v0.10.0", "v0.9.0", true}, - {"v2.0.0", "v1.99.99", true}, - {"v0.5.1", "dev", false}, - {"dev", "v0.5.0", false}, - {"invalid", "v0.5.0", false}, - {"v0.5.0", "invalid", false}, - } - - for _, tt := range tests { - t.Run(tt.v+"_vs_"+tt.w, func(t *testing.T) { - got := versionGreaterThan(tt.v, tt.w) - if got != tt.want { - t.Errorf("versionGreaterThan(%q, %q) = %v, want %v", tt.v, tt.w, got, tt.want) - } - }) - } -} diff --git a/internal/useragent/useragent.go b/internal/useragent/useragent.go deleted file mode 100644 index 9d8bcfd..0000000 --- a/internal/useragent/useragent.go +++ /dev/null @@ -1,24 +0,0 @@ -package useragent - -import ( - "fmt" - "os" - "runtime" -) - -var version = "dev" - -// SetVersion sets the CLI version used in the User-Agent string. -// Called from root command with build-time injected version. -func SetVersion(v string) { version = v } - -// String returns a structured User-Agent string for HTTP requests. -// Format: CNAP CLI/{version} ({os}; {arch}; {hostname}) -// Example: CNAP CLI/1.2.0 (darwin; arm64; Robins-MacBook-Pro.local) -func String() string { - host, _ := os.Hostname() - if host == "" { - host = "unknown" - } - return fmt.Sprintf("CNAP CLI/%s (%s; %s; %s)", version, runtime.GOOS, runtime.GOARCH, host) -} diff --git a/mise.toml b/mise.toml index cab42a7..30e2937 100644 --- a/mise.toml +++ b/mise.toml @@ -1,5 +1,37 @@ [tools] -go = "1.26.0" -task = "3.48.0" -golangci-lint = "2.10.1" -goreleaser = "2.13.3" +bun = "1.3.7" + +[env] +AKUA_OPENAPI_URL = "https://api.akua.dev/v1/openapi.json" + +[tasks.dev] +description = "Run the TypeScript CLI entrypoint" +run = "bun run dev --" + +[tasks.build] +description = "Typecheck and build JavaScript output" +run = "bun run build" + +[tasks."build:binary"] +description = "Compile a self-contained akua executable with Bun" +run = "bun run build:binary" + +[tasks.test] +description = "Run tests" +run = "bun test" + +[tasks."spec:fetch"] +description = "Fetch the production OpenAPI spec snapshot" +run = "bun run spec:fetch" + +[tasks.generate] +description = "Regenerate generated CLI artifacts" +run = "bun run generate" + +[tasks."generate:check"] +description = "Verify generated CLI artifacts are current" +run = "bun run generate:check" + +[tasks.check] +description = "Run the local validation suite" +depends = ["generate:check", "build", "test"] diff --git a/openapi/public.json b/openapi/public.json new file mode 100644 index 0000000..b433ecd --- /dev/null +++ b/openapi/public.json @@ -0,0 +1,46161 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Akua API", + "version": "1.0.0", + "description": "Public API for managing Akua workspaces, clusters, products, and installs.\n\nAuthenticate with a workspace API token via the `Authorization: Bearer sk_akua_...` header.\n\nA workspace-owned token implies its workspace. Broad tokens select the active workspace via the optional `Akua-Context` header.", + "contact": { + "name": "Akua API support", + "email": "support@akua.dev", + "url": "https://akua.dev/docs" + } + }, + "servers": [ + { + "url": "https://api.akua.dev/v1", + "description": "Production" + } + ], + "tags": [ + { + "name": "Auth", + "description": "Authentication and token management." + }, + { + "name": "Agents", + "description": "Agent identities and configuration." + }, + { + "name": "Agent sessions", + "description": "Durable agent conversations and tasks." + }, + { + "name": "Agent turns", + "description": "Submitted agent work and event emission." + }, + { + "name": "Agent events", + "description": "Normalized agent event history and streams." + }, + { + "name": "Custom domains", + "description": "Workspace custom domains and routing targets." + }, + { + "name": "Cloudflare", + "description": "Cloudflare account credentials and gateway control." + }, + { + "name": "Clusters", + "description": "Kubernetes clusters and cluster access operations." + }, + { + "name": "ComputeConfigs", + "description": "Workspace compute provider configurations." + }, + { + "name": "Entitlements", + "description": "Effective workspace capabilities and limits." + }, + { + "name": "Dashboards", + "description": "Dashboard and widget resources." + }, + { + "name": "Installs", + "description": "Product installation and render operations." + }, + { + "name": "Machines", + "description": "Compute machines and lifecycle events." + }, + { + "name": "Notifications", + "description": "User notification state." + }, + { + "name": "Offer Channels", + "description": "Private offer channels and policy versions." + }, + { + "name": "Offers", + "description": "Marketplace offers and redemption tracking." + }, + { + "name": "Operations", + "description": "Long-running operation status and controls." + }, + { + "name": "Order Drafts", + "description": "Draft checkout orders and checkout sessions." + }, + { + "name": "Organizations", + "description": "Organizations, memberships, and managed workspaces." + }, + { + "name": "Packages", + "description": "Software packages, versions, and input schemas." + }, + { + "name": "Products", + "description": "Marketplace product catalog resources." + }, + { + "name": "Preview hostnames", + "description": "Install preview hostnames and routing state." + }, + { + "name": "Quotas", + "description": "Workspace quota limits and usage." + }, + { + "name": "Regions", + "description": "Available deployment regions." + }, + { + "name": "Registry", + "description": "Container registry credentials and repositories." + }, + { + "name": "Repository change requests", + "description": "Fork-backed repository change reviews and lifecycle actions." + }, + { + "name": "Repositories", + "description": "Source repositories available to the workspace." + }, + { + "name": "Secrets", + "description": "Workspace secrets and secret versions." + }, + { + "name": "Snippets", + "description": "Reusable snippets and snippet runs." + }, + { + "name": "Workspace subdomains", + "description": "Workspace subdomain identity." + }, + { + "name": "Workspaces", + "description": "Workspace resources, members, and billing state." + } + ], + "components": { + "securitySchemes": { + "BearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "workspace API token (sk_akua_...) or OAuth2 JWT. Create tokens at https://akua.dev/developers/api-tokens" + } + }, + "schemas": { + "ComputeMachine": { + "type": "object", + "properties": { + "provider_id": { + "type": "string", + "example": "compute://abc123" + }, + "node_name": { + "type": "string", + "example": "worker-xl8r2" + }, + "status": { + "type": "string", + "example": "provisioning" + } + }, + "required": [ + "provider_id", + "node_name", + "status" + ] + }, + "ApiErrorResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + false + ] + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiErrorEntry" + } + }, + "result": { + "type": "object", + "properties": {}, + "description": "Always empty for error responses" + } + }, + "required": [ + "success", + "errors", + "result" + ] + }, + "ApiErrorEntry": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 7002, + "description": "Machine-readable error code" + }, + "message": { + "type": "string", + "example": "Resource not found", + "description": "Human-readable error message" + }, + "path": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "body", + "name" + ], + "description": "Field path that caused the error, when applicable" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "code", + "message" + ] + }, + "ComputeError": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "InsufficientCapacity", + "description": "Machine-readable error type (e.g., InsufficientCapacity, NodeClaimNotFound)" + }, + "message": { + "type": "string", + "example": "cpx31 out of stock in fsn1" + } + }, + "required": [ + "type", + "message" + ] + }, + "InstanceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "cpx31" + }, + "arch": { + "type": "string", + "example": "amd64" + }, + "cpu": { + "type": "number", + "example": 4 + }, + "memory_mib": { + "type": "number", + "example": 8192 + }, + "storage_mib": { + "type": "number", + "example": 163840 + }, + "price_per_hour": { + "type": "number", + "example": 0.0208 + }, + "available": { + "type": "boolean", + "example": true + }, + "zone": { + "type": "string", + "example": "fsn1" + }, + "capacity_type": { + "type": "string", + "example": "on-demand" + } + }, + "required": [ + "name", + "arch", + "cpu", + "memory_mib", + "storage_mib", + "price_per_hour", + "available" + ] + }, + "DriftResult": { + "type": "object", + "properties": { + "drifted": { + "type": "boolean" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "drifted" + ] + }, + "Suspension": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "cluster_id": { + "type": "string" + }, + "server_type": { + "type": "string", + "example": "cpx31" + }, + "location": { + "type": "string", + "example": "fsn1" + }, + "hostname": { + "type": "string", + "example": "node-xl8r2abc" + }, + "reason": { + "type": "string", + "enum": [ + "manual", + "downgrade" + ] + }, + "provider_suspend_data": { + "type": "object", + "properties": { + "provider": { + "type": "string" + }, + "snapshot_id": { + "type": "number" + }, + "size_gb": { + "type": "number" + } + }, + "required": [ + "provider", + "snapshot_id", + "size_gb" + ] + }, + "monthly_cost_cents": { + "type": "number" + }, + "expires_at": { + "type": "number" + }, + "created_at": { + "type": "number" + } + }, + "required": [ + "id", + "workspace_id", + "cluster_id", + "server_type", + "location", + "hostname", + "reason", + "provider_suspend_data", + "monthly_cost_cents", + "expires_at", + "created_at" + ] + }, + "ComputeConfigList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ComputeConfig" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "ComputeConfig": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "type": "string", + "example": "hcloud" + }, + "provider_config": { + "type": "object", + "properties": { + "provider": { + "type": "string" + }, + "region": { + "type": "string" + }, + "image": { + "type": "string" + }, + "machine_type_filter": { + "type": "string", + "nullable": true, + "description": "Glob pattern to filter instance types (e.g., \"cx*\", \"cpx*\")" + } + }, + "required": [ + "provider", + "region", + "image", + "machine_type_filter" + ] + }, + "secret_id": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "number" + } + }, + "required": [ + "id", + "name", + "provider", + "provider_config", + "secret_id", + "created_at" + ] + }, + "CreatedComputeConfig": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, + "SnippetList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Snippet" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Snippet": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "example": "snp_j572abc123def456" + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/dashboards/snippets/snp_j572abc123def456" + }, + "name": { + "type": "string", + "example": "Cluster Resource Audit" + }, + "description": { + "type": "string", + "nullable": true, + "example": "Checks resource requests and limits" + }, + "code": { + "type": "string", + "example": "async () => { ... }", + "description": "Async JavaScript function body executed in a sandboxed runtime. Has access to platform.request() for API calls." + }, + "display_type": { + "type": "string", + "enum": [ + "table", + "stat", + "json", + "logs" + ], + "description": "Controls how the snippet result is rendered in dashboard widgets", + "example": "table" + }, + "visibility": { + "type": "string", + "enum": [ + "workspace", + "session" + ], + "description": "Whether the snippet is reusable workspace state or scoped to an agent session." + }, + "origin": { + "type": "string", + "enum": [ + "user", + "agent", + "system" + ], + "description": "Who authored the snippet descriptor." + }, + "agent_session_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "agent_turn_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "purpose": { + "type": "string", + "enum": [ + "general", + "prepared_action", + "reactive_read", + "widget" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "example": "ws_j572abc123def456" + }, + "created_by": { + "type": "string", + "description": "User ID of the snippet creator" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "name", + "description", + "code", + "display_type", + "visibility", + "origin", + "agent_session_id", + "agent_turn_id", + "purpose", + "workspace_id", + "created_by", + "created_at", + "updated_at", + "etag" + ] + }, + "SnippetUsageList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SnippetUsage" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "SnippetUsage": { + "type": "object", + "properties": { + "snippet_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "dashboard_count": { + "type": "integer", + "minimum": 0 + }, + "dashboards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SnippetUsageDashboard" + } + } + }, + "required": [ + "snippet_id", + "dashboard_count", + "dashboards" + ] + }, + "SnippetUsageDashboard": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "id", + "name", + "description", + "workspace_id" + ] + }, + "ExecuteSnippetResponse": { + "type": "object", + "properties": { + "result": { + "nullable": true + }, + "error": { + "type": "string" + }, + "stats": { + "type": "object", + "properties": { + "cpu_time_ms": { + "type": "number" + }, + "wall_time_ms": { + "type": "number" + }, + "heap_used_bytes": { + "type": "number" + } + }, + "required": [ + "cpu_time_ms", + "wall_time_ms", + "heap_used_bytes" + ] + } + }, + "required": [ + "stats" + ] + }, + "ExecuteSnippetBody": { + "type": "object", + "properties": { + "code": { + "type": "string", + "minLength": 1, + "maxLength": 50000, + "description": "Async JavaScript function body. Executed in a sandboxed runtime with access to platform.request()." + } + }, + "required": [ + "code" + ], + "additionalProperties": false + }, + "SnippetRun": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "snippet_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "agent_session_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "agent_turn_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "state": { + "type": "string", + "enum": [ + "succeeded", + "failed", + "timed_out" + ], + "description": "Terminal run state in past participle form." + }, + "overrides": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "output": { + "nullable": true + }, + "error": { + "$ref": "#/components/schemas/SnippetRunError" + }, + "duration_ms": { + "type": "number" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "snippet_id", + "agent_session_id", + "agent_turn_id", + "state", + "duration_ms", + "created_at", + "etag" + ] + }, + "SnippetRunError": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "details": { + "nullable": true + } + }, + "required": [ + "code", + "message" + ] + }, + "CreateSnippetRunBody": { + "type": "object", + "properties": { + "overrides": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "agent_turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "additionalProperties": false + }, + "SnippetRunList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SnippetRun" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "DashboardList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Dashboard" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Dashboard": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "j572abc123def456" + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/dashboards/dash_j572abc123def456" + }, + "name": { + "type": "string", + "example": "Cluster Overview" + }, + "description": { + "type": "string", + "nullable": true, + "description": "Optional dashboard description" + }, + "workspace_id": { + "type": "string" + }, + "widgets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Widget" + }, + "description": "Output-only denormalized widget list for dashboard read models." + }, + "created_by": { + "type": "string", + "description": "User ID of the dashboard creator" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "name", + "description", + "workspace_id", + "widgets", + "created_by", + "created_at", + "updated_at", + "etag" + ] + }, + "Widget": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "dashboard_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "widget_type": { + "type": "string", + "enum": [ + "snippet" + ], + "description": "Dashboard widget descriptor type. `snippet` is the first concrete type; future agent-authored widgets extend this field." + }, + "snippet_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "position": { + "type": "integer" + }, + "col_span": { + "anyOf": [ + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + } + ] + }, + "display_type": { + "type": "string", + "nullable": true, + "enum": [ + "table", + "stat", + "json", + "logs", + null + ], + "description": "Controls how the snippet result is rendered in dashboard widgets" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "dashboard_id", + "widget_type", + "snippet_id", + "position", + "col_span", + "display_type", + "created_at", + "updated_at", + "etag" + ] + }, + "WidgetList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Widget" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "OperationEnvelope": { + "type": "object", + "properties": { + "operation_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "operation_id" + ] + }, + "MachineList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Machine" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Machine": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "compute_config_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "provider_id": { + "type": "string", + "description": "Provider URI identifier in canonical form (for example, compute://hcloud/server-1234).", + "example": "compute://hcloud/server-1234" + }, + "provider_resource": { + "type": "object", + "properties": { + "identity_kind": { + "type": "string", + "enum": [ + "recyclable", + "persistent" + ] + }, + "public_ip": { + "type": "string", + "nullable": true + }, + "floating_ip": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "ipv4": { + "type": "string" + } + }, + "required": [ + "id", + "ipv4" + ] + } + }, + "required": [ + "identity_kind", + "public_ip" + ] + }, + "name": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "ACTIVE", + "PROVISIONING", + "SUSPENDING", + "SUSPENDED", + "RESUMING", + "DELETING" + ], + "description": "Machine lifecycle state." + }, + "reconciling": { + "type": "boolean" + }, + "current_suspension": { + "type": "object", + "properties": { + "event_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "snapshot_ref": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "hcloud" + ] + }, + "snapshot_id": { + "type": "integer" + }, + "size_gb": { + "type": "number" + } + }, + "required": [ + "provider", + "snapshot_id", + "size_gb" + ] + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "monthly_cost_cents": { + "type": "integer" + }, + "reason": { + "type": "string", + "enum": [ + "manual", + "downgrade" + ] + } + }, + "required": [ + "event_id", + "snapshot_ref", + "expires_at", + "monthly_cost_cents", + "reason" + ] + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "cluster_id", + "compute_config_id", + "provider_id", + "provider_resource", + "state", + "reconciling", + "created_at", + "updated_at", + "etag" + ] + }, + "SuspendMachineBody": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "enum": [ + "manual", + "downgrade" + ] + } + }, + "additionalProperties": false + }, + "ResumeMachineBody": { + "type": "object", + "properties": {}, + "additionalProperties": false + }, + "DriftReport": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Drift report ID." + }, + "machine_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "state": { + "type": "string", + "enum": [ + "in_sync", + "drifted" + ], + "description": "Machine drift comparison state." + }, + "delta": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "provider_snapshot": { + "type": "object", + "properties": { + "provider": { + "type": "string" + }, + "raw_attrs": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "provider", + "raw_attrs" + ] + }, + "etag": { + "type": "string" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "machine_id", + "state", + "etag", + "created_at", + "started_at", + "expires_at" + ] + }, + "DriftReportList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DriftReport" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "SuspensionEventList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SuspensionEvent" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "SuspensionEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "machine_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "state": { + "type": "string", + "enum": [ + "in_progress", + "completed", + "resumed", + "expired" + ], + "description": "Suspension-event lifecycle state." + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "resumed_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "snapshot_ref": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "hcloud" + ] + }, + "snapshot_id": { + "type": "integer" + }, + "size_gb": { + "type": "number" + } + }, + "required": [ + "provider", + "snapshot_id", + "size_gb" + ] + }, + "monthly_cost_cents": { + "type": "integer" + }, + "total_cost_cents": { + "type": "integer" + }, + "reason": { + "type": "string", + "enum": [ + "manual", + "downgrade" + ] + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "machine_id", + "state", + "started_at", + "expires_at", + "snapshot_ref", + "monthly_cost_cents", + "reason", + "etag" + ] + }, + "CredentialScope": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "system" + ], + "description": "Use system-managed provider credentials." + } + }, + "required": [ + "kind" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "byom" + ] + }, + "secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "secret_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "secret_id" + ], + "additionalProperties": false + } + ] + }, + "ProductList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Product": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "example": "prod_j572abc123def456" + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/products/prod_j572abc123def456" + }, + "name": { + "type": "string", + "example": "PostgreSQL Managed" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "example": "pkg_j572abc123def456" + }, + "version_pin": { + "$ref": "#/components/schemas/PackageVersionPin" + }, + "default_version_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 55, + "description": "Concrete PackageVersion currently resolved by the version pin, or null when latest has no published version yet." + } + }, + "required": [ + "id", + "version_pin", + "default_version_id" + ], + "additionalProperties": false, + "description": "Reference to the Package backing this product. Fetch full details via `GET /v1/packages/{id}`." + }, + "custom_image": { + "type": "string", + "description": "Custom display image URL — overrides the package logo on customer-facing pages" + }, + "custom_description": { + "type": "string", + "description": "Custom display description — overrides the package description" + }, + "marketplace": { + "$ref": "#/components/schemas/ProductMarketplaceState" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "active", + "archived" + ], + "description": "Product lifecycle state." + }, + "archived_at": { + "type": "integer", + "minimum": 0, + "description": "When the product was archived, expressed as Unix seconds since epoch." + }, + "archive_reason": { + "type": "string", + "description": "Reason supplied by the seller when archiving." + } + }, + "required": [ + "id", + "html_url", + "name", + "workspace_id", + "package", + "marketplace", + "created_at", + "updated_at", + "etag", + "state" + ] + }, + "PackageVersionPin": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "latest" + ] + } + }, + "required": [ + "kind" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "pinned" + ] + }, + "version": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$", + "example": "1.2.3" + } + }, + "required": [ + "kind", + "version" + ], + "additionalProperties": false + } + ] + }, + "ProductMarketplaceState": { + "type": "object", + "nullable": true, + "properties": { + "published": { + "type": "boolean", + "description": "Whether the product is publicly visible on the marketplace" + } + }, + "required": [ + "published" + ], + "additionalProperties": false, + "description": "Marketplace listing configuration. When null the product is not listed." + }, + "DashboardProductList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardProduct" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "DashboardProduct": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "example": "prod_j572abc123def456" + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/products/prod_j572abc123def456" + }, + "name": { + "type": "string", + "example": "PostgreSQL Managed" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "example": "pkg_j572abc123def456" + }, + "version_pin": { + "$ref": "#/components/schemas/PackageVersionPin" + }, + "default_version_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 55, + "description": "Concrete PackageVersion currently resolved by the version pin, or null when latest has no published version yet." + } + }, + "required": [ + "id", + "version_pin", + "default_version_id" + ], + "additionalProperties": false, + "description": "Reference to the Package backing this product. Fetch full details via `GET /v1/packages/{id}`." + }, + "custom_image": { + "type": "string", + "description": "Custom display image URL — overrides the package logo on dashboard catalog rows" + }, + "marketplace": { + "$ref": "#/components/schemas/ProductMarketplaceState" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "active", + "archived" + ], + "description": "Product lifecycle state." + }, + "archived_at": { + "type": "integer", + "minimum": 0, + "description": "When the product was archived, expressed as Unix seconds since epoch." + }, + "archive_reason": { + "type": "string", + "description": "Reason supplied by the seller when archiving." + }, + "cluster_count": { + "type": "integer", + "minimum": 0 + }, + "region_count": { + "type": "integer", + "minimum": 0 + }, + "offer_count": { + "type": "integer", + "minimum": 0 + }, + "install_count": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "id", + "html_url", + "name", + "workspace_id", + "package", + "marketplace", + "created_at", + "updated_at", + "etag", + "state", + "cluster_count", + "region_count", + "offer_count", + "install_count" + ] + }, + "MarketplaceProductList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MarketplaceProduct" + } + }, + "MarketplaceProduct": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "name": { + "type": "string" + }, + "regions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MarketplaceRegion" + } + }, + "hasStripe": { + "type": "boolean" + }, + "marketplace": { + "$ref": "#/components/schemas/MarketplaceProductState" + }, + "settings": { + "$ref": "#/components/schemas/MarketplaceProductSettings" + }, + "visibleOffer": { + "$ref": "#/components/schemas/MarketplaceVisibleOffer" + } + }, + "required": [ + "id", + "name", + "regions", + "hasStripe" + ] + }, + "MarketplaceRegion": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "_creationTime": { + "type": "number" + }, + "workspaceId": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "name": { + "type": "string" + }, + "icon": { + "type": "string" + } + }, + "required": [ + "_id", + "_creationTime", + "workspaceId", + "name" + ] + }, + "MarketplaceProductState": { + "type": "object", + "properties": { + "published": { + "type": "boolean" + }, + "externalUrl": { + "type": "string" + } + }, + "required": [ + "published" + ] + }, + "MarketplaceProductSettings": { + "type": "object", + "properties": { + "customImage": { + "type": "string" + }, + "customDescription": { + "type": "string" + }, + "showSources": { + "type": "boolean" + } + } + }, + "MarketplaceVisibleOffer": { + "type": "object", + "properties": { + "shortHash": { + "type": "string" + } + }, + "required": [ + "shortHash" + ] + }, + "MarketplaceProductDetail": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "name": { + "type": "string" + }, + "valuesSchema": { + "type": "string" + }, + "regions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MarketplaceRegion" + } + }, + "pricing": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MarketplaceProductPricing" + } + }, + "isOwner": { + "type": "boolean" + }, + "settings": { + "$ref": "#/components/schemas/MarketplaceProductSettings" + }, + "stripePriceIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "marketplace": { + "$ref": "#/components/schemas/MarketplaceProductState" + }, + "visibleOffer": { + "$ref": "#/components/schemas/MarketplaceVisibleOffer" + } + }, + "required": [ + "id", + "name", + "regions", + "pricing", + "isOwner", + "settings", + "stripePriceIds" + ] + }, + "MarketplaceProductPricing": { + "type": "object", + "properties": { + "price": { + "type": "number" + }, + "recurring": { + "type": "string" + }, + "currency": { + "type": "string" + } + }, + "required": [ + "price", + "currency" + ] + }, + "CreateProductBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 2, + "maxLength": 64, + "example": "PostgreSQL Managed" + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_pin": { + "$ref": "#/components/schemas/PackageVersionPin" + }, + "custom_image": { + "type": "string", + "format": "uri", + "description": "Custom display image URL — overrides the package logo" + }, + "custom_description": { + "type": "string", + "maxLength": 500, + "description": "Custom display description — overrides the package description" + }, + "marketplace": { + "$ref": "#/components/schemas/ProductMarketplace" + } + }, + "required": [ + "name", + "package_id", + "package_version_pin" + ], + "additionalProperties": false + }, + "ProductMarketplace": { + "type": "object", + "properties": { + "published": { + "type": "boolean", + "description": "Whether the product is publicly visible on the marketplace" + } + }, + "required": [ + "published" + ], + "additionalProperties": false, + "description": "Marketplace listing config. Omit to keep the product unlisted." + }, + "UpdateProductBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 2, + "maxLength": 64, + "example": "PostgreSQL Managed" + }, + "package_version_pin": { + "$ref": "#/components/schemas/PackageVersionPin" + }, + "custom_image": { + "type": "string", + "nullable": true, + "format": "uri" + }, + "custom_description": { + "type": "string", + "nullable": true, + "maxLength": 500 + }, + "marketplace": { + "$ref": "#/components/schemas/ProductMarketplace" + } + }, + "additionalProperties": false + }, + "ArchiveProductBody": { + "type": "object", + "properties": { + "cascade_offers": { + "type": "boolean", + "default": false + }, + "archive_reason": { + "type": "string", + "maxLength": 500 + } + }, + "additionalProperties": false + }, + "OfferChannel": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "authority_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "display_name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "partner_organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "product_scope": { + "$ref": "#/components/schemas/OfferChannelProductScope" + }, + "state": { + "type": "string", + "enum": [ + "active", + "archived" + ] + }, + "commercial_authority": { + "type": "string", + "enum": [ + "platform", + "workspace" + ] + }, + "active_channel_policy_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "display_name", + "product_scope", + "state", + "commercial_authority", + "created_at", + "etag" + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "OfferChannelProductScope": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "all_products" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "selected_products" + ] + }, + "product_ids": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "maxItems": 100 + } + }, + "required": [ + "type", + "product_ids" + ] + } + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "CreateOfferChannelBody": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "display_name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "partner_organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "product_scope": { + "$ref": "#/components/schemas/OfferChannelProductScope" + }, + "commercial_authority": { + "type": "string", + "enum": [ + "platform", + "workspace" + ], + "default": "platform" + } + }, + "required": [ + "display_name", + "product_scope" + ], + "additionalProperties": false, + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "OfferChannelList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OfferChannelListItem" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "OfferChannelListItem": { + "allOf": [ + { + "$ref": "#/components/schemas/OfferChannel" + }, + { + "type": "object", + "properties": { + "active_policy": { + "$ref": "#/components/schemas/ChannelPolicy" + } + } + } + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "ChannelPolicy": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "version": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "state": { + "type": "string", + "enum": [ + "draft", + "approved", + "active", + "archived" + ] + }, + "policy": { + "$ref": "#/components/schemas/ChannelPolicyPayload" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "approved_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "activated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "offer_channel_id", + "version", + "state", + "policy", + "created_at", + "etag" + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "ChannelPolicyPayload": { + "type": "object", + "properties": { + "pricing_policy": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "fixed_or_range" + ] + }, + "currency": { + "type": "string", + "enum": [ + "eur", + "usd" + ] + }, + "default_unit_amount": { + "type": "integer", + "minimum": 0 + }, + "minimum_unit_amount": { + "type": "integer", + "minimum": 0 + }, + "maximum_unit_amount": { + "type": "integer", + "minimum": 0 + }, + "interval": { + "$ref": "#/components/schemas/PricingInterval" + } + }, + "required": [ + "type", + "currency", + "default_unit_amount", + "minimum_unit_amount", + "maximum_unit_amount", + "interval" + ], + "additionalProperties": false + }, + "settlement_policy": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "platform_resolved" + ] + }, + "allowed_commercial_modes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommercialMode" + }, + "minItems": 1 + } + }, + "required": [ + "type", + "allowed_commercial_modes" + ], + "additionalProperties": false + }, + "approval_policy": { + "type": "object", + "properties": { + "paid_offers": { + "type": "string", + "enum": [ + "requires_platform_approval", + "auto_approved" + ] + }, + "non_billable_test_offers": { + "type": "string", + "enum": [ + "requires_platform_approval", + "auto_approved" + ] + } + }, + "required": [ + "paid_offers", + "non_billable_test_offers" + ], + "additionalProperties": false + }, + "trusted_testing_policy": { + "type": "object", + "properties": { + "stripe_checkout_environment": { + "type": "string", + "enum": [ + "sandbox" + ] + } + }, + "required": [ + "stripe_checkout_environment" + ], + "additionalProperties": false + }, + "support_access_policy": { + "$ref": "#/components/schemas/OfferSupportScope" + } + }, + "required": [ + "pricing_policy", + "settlement_policy", + "approval_policy", + "support_access_policy" + ], + "additionalProperties": false, + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "PricingInterval": { + "type": "string", + "enum": [ + "month", + "year" + ] + }, + "CommercialMode": { + "type": "string", + "enum": [ + "paid", + "non_billable_test" + ], + "description": "Customer commercial path requested for an offer. `paid` routes through checkout when policy requires it; `non_billable_test` creates a non-billable test offer when policy allows it." + }, + "OfferSupportScope": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "scoped_support_relationship" + ] + }, + "visibility": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "install_state", + "app_urls" + ] + }, + "maxItems": 20 + } + }, + "required": [ + "type", + "visibility" + ], + "additionalProperties": false + }, + "CreateChannelPolicyBody": { + "type": "object", + "properties": { + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "policy": { + "$ref": "#/components/schemas/ChannelPolicyPayload" + } + }, + "required": [ + "offer_channel_id", + "policy" + ], + "additionalProperties": false, + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "ChannelPolicyList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelPolicy" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "OfferList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Offer" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Offer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID" + }, + "short_hash": { + "type": "string", + "description": "8-char base62 code that appears in the customer-clicked URL `/i/`", + "example": "aB3xK9pQ" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace that receives the offer outcome when visible to the caller" + }, + "created_by": { + "type": "string", + "description": "User ID of the seller who issued the offer" + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID" + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Package ID" + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Package version ID — pinned at create time" + }, + "input_schema": { + "type": "object", + "additionalProperties": { + "nullable": true + }, + "description": "JSON Schema 2020-12 with x-ui extensions for the pinned package version. Present on customer resolve responses so the install wizard can render the configure step." + }, + "allowed_emails": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Empty / omitted = anyone authed can claim. Non-empty = the customer's verified email must match. Only returned to authed callers." + }, + "field_values": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "nullable": true, + "description": "Pre-fill value for this schema property" + }, + "locked": { + "type": "boolean", + "description": "When true the customer cannot override; submit ignores client value" + } + }, + "required": [ + "value", + "locked" + ] + }, + "description": "Seller pre-fills keyed by package input-schema property name. Only returned to authed callers whose email matches the allowlist." + }, + "tier": { + "type": "string", + "description": "Suggested billing tier" + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Region pin" + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Cluster pin" + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Offer Channel that resolved private-offer policy for this offer" + }, + "commercial_mode": { + "$ref": "#/components/schemas/CommercialMode" + }, + "approval_state": { + "$ref": "#/components/schemas/OfferApprovalState" + }, + "requested_policy_snapshot": { + "$ref": "#/components/schemas/OfferPolicySnapshot" + }, + "approved_policy_snapshot": { + "$ref": "#/components/schemas/OfferPolicySnapshot" + }, + "notes": { + "type": "string" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "max_uses": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "order_ttl_minutes": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 1440, + "description": "Per-redemption order TTL in minutes. Defaults to 120; capped at 1440 (24h)." + }, + "used_count": { + "type": "integer", + "minimum": 0 + }, + "archived_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "status": { + "$ref": "#/components/schemas/OfferStatus" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "product_name": { + "type": "string", + "description": "Display name of the offered product" + }, + "image_url": { + "type": "string", + "description": "Logo or icon URL for the customer landing page" + }, + "seller_name": { + "type": "string", + "description": "Display name of the seller who issued this offer" + } + }, + "required": [ + "id", + "short_hash", + "package_id", + "package_version_id", + "status", + "created_at" + ] + }, + "OfferApprovalState": { + "type": "string", + "enum": [ + "not_required", + "pending", + "approved", + "rejected" + ] + }, + "OfferPolicySnapshot": { + "type": "object", + "properties": { + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "channel_policy_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "channel_policy_version": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "commercial_mode": { + "$ref": "#/components/schemas/CommercialMode" + }, + "approval_required": { + "type": "boolean" + }, + "checkout_required": { + "type": "boolean" + }, + "approval_mode": { + "type": "string", + "enum": [ + "requires_platform_approval", + "auto_approved_within_policy" + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "checkout_environment": { + "type": "string", + "enum": [ + "none", + "stripe_live", + "stripe_sandbox" + ], + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "pricing_bounds": { + "$ref": "#/components/schemas/OfferPricingBounds" + }, + "pricing_summary": { + "$ref": "#/components/schemas/OfferPricingSummary" + }, + "support_scope": { + "$ref": "#/components/schemas/OfferSupportScope" + }, + "blocking_reasons": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "required": [ + "offer_channel_id", + "channel_policy_id", + "channel_policy_version", + "commercial_mode", + "approval_required", + "checkout_required", + "support_scope" + ] + }, + "OfferPricingBounds": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "enum": [ + "eur", + "usd" + ] + }, + "default_unit_amount": { + "type": "integer", + "minimum": 0 + }, + "minimum_unit_amount": { + "type": "integer", + "minimum": 0 + }, + "maximum_unit_amount": { + "type": "integer", + "minimum": 0 + }, + "interval": { + "$ref": "#/components/schemas/PricingInterval" + } + }, + "required": [ + "currency", + "default_unit_amount", + "minimum_unit_amount", + "maximum_unit_amount", + "interval" + ], + "additionalProperties": false, + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "OfferPricingSummary": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "enum": [ + "eur", + "usd" + ] + }, + "unit_amount": { + "type": "integer", + "minimum": 0 + }, + "interval": { + "$ref": "#/components/schemas/PricingInterval" + }, + "source": { + "type": "string", + "enum": [ + "channel_policy", + "request" + ] + } + }, + "required": [ + "currency", + "unit_amount", + "interval", + "source" + ] + }, + "OfferStatus": { + "type": "string", + "enum": [ + "active", + "archived", + "expired", + "redeemed" + ], + "description": "Computed lifecycle status — never set directly; derived from row state." + }, + "PreviewOfferBody": { + "type": "object", + "properties": { + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Package version ID to preview against. Preview requires a concrete package version because no offer row is created to store a resolved product pin." + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID for channel policy attribution." + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Existing customer workspace used for preview context." + }, + "allowed_emails": { + "type": "array", + "items": { + "type": "string", + "maxLength": 254, + "format": "email" + }, + "maxItems": 50, + "description": "Verified customer email allowlist used for preview context." + }, + "field_values": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "nullable": true, + "description": "Pre-fill value for this schema property" + }, + "locked": { + "type": "boolean", + "description": "When true the customer cannot override; submit ignores client value" + } + }, + "required": [ + "value", + "locked" + ] + }, + "description": "Package input pre-fills used for preview context." + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Delivery region pin used for preview context." + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Delivery cluster pin used for preview context." + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Offer Channel whose active policy is previewed." + }, + "commercial_mode": { + "allOf": [ + { + "$ref": "#/components/schemas/CommercialMode" + }, + { + "description": "Requested customer path for channel policy resolution. This is not settlement authority; the active channel policy decides the final terms." + } + ] + }, + "pricing_request": { + "$ref": "#/components/schemas/OfferPricingRequest" + } + }, + "required": [ + "package_version_id", + "product_id", + "offer_channel_id", + "commercial_mode" + ], + "additionalProperties": false, + "description": "Preview channel policy resolution for a concrete package version and product before creating an offer.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "OfferPricingRequest": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "enum": [ + "eur", + "usd" + ], + "example": "eur", + "description": "ISO currency code for the requested price." + }, + "unit_amount": { + "type": "integer", + "minimum": 0, + "maximum": 100000000, + "description": "Requested price in the smallest currency unit, for example cents for EUR or USD." + }, + "interval": { + "allOf": [ + { + "$ref": "#/components/schemas/PricingInterval" + }, + { + "description": "Billing interval for the requested price." + } + ] + } + }, + "required": [ + "currency", + "unit_amount", + "interval" + ], + "additionalProperties": false, + "description": "Requested customer-visible price for channel policy resolution. The active policy validates the request before the offer is created." + }, + "OfferCreated": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID" + }, + "short_hash": { + "type": "string" + } + }, + "required": [ + "id", + "short_hash" + ] + }, + "CreateOfferBody": { + "anyOf": [ + { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID for attribution and package-version resolution. Required for channel-backed offers. When `package_version_id` is omitted, the server uses the product’s current package version pin." + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Package version ID to pin explicitly at create time. Optional when `product_id` is supplied; if both are supplied, this value overrides the product’s current package version pin." + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Trusted-partner delivery target. When supplied, the redeemed order is created for this existing customer workspace instead of selecting or creating a workspace during checkout. Requires the target-existing-workspace entitlement and customer workspace membership.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Trusted-partner delivery region pin. Requires a fixed delivery workspace or pinned cluster and the target-managed-workspace entitlement.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Trusted-partner delivery cluster pin. The cluster must belong to the delivery workspace and requires the target-managed-workspace entitlement.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "allowed_emails": { + "type": "array", + "items": { + "type": "string", + "maxLength": 254, + "format": "email" + }, + "maxItems": 50, + "description": "Verified customer email allowlist. Empty or omitted means any authenticated customer can redeem the offer." + }, + "field_values": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "nullable": true, + "description": "Pre-fill value for this schema property" + }, + "locked": { + "type": "boolean", + "description": "When true the customer cannot override; submit ignores client value" + } + }, + "required": [ + "value", + "locked" + ] + }, + "description": "Package input pre-fills keyed by input-schema property name. Values are validated against the resolved package version input schema before the offer is created." + }, + "tier": { + "type": "string", + "maxLength": 32, + "description": "Legacy advisory billing tier for non-channel offers. Do not send this with `offer_channel_id`; channel-backed offers use `commercial_mode` and `pricing_request`." + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Offer Channel whose active policy resolves approval, checkout, support, and pricing terms. Requires `product_id`." + }, + "commercial_mode": { + "allOf": [ + { + "$ref": "#/components/schemas/CommercialMode" + }, + { + "description": "Requested customer path for channel policy resolution. This is not settlement authority; the active channel policy decides the final terms." + } + ] + }, + "pricing_request": { + "$ref": "#/components/schemas/OfferPricingRequest" + }, + "notes": { + "type": "string", + "maxLength": 500, + "description": "Seller-private note for operators reviewing or supporting the offer. Not shown to the customer." + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Unix timestamp in seconds after which the offer can no longer be redeemed. Omit for no explicit expiration." + }, + "max_uses": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 10000, + "description": "Maximum number of successful redemptions allowed for this offer. Omit for the default single-use behavior." + }, + "order_ttl_minutes": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 1440, + "description": "Per-redemption order TTL in minutes. Defaults to 120; capped at 1440 (24h)." + } + }, + "required": [ + "product_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Package version ID to pin explicitly at create time. Optional when `product_id` is supplied; if both are supplied, this value overrides the product’s current package version pin." + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID for attribution and package-version resolution. Required for channel-backed offers. When `package_version_id` is omitted, the server uses the product’s current package version pin." + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Trusted-partner delivery target. When supplied, the redeemed order is created for this existing customer workspace instead of selecting or creating a workspace during checkout. Requires the target-existing-workspace entitlement and customer workspace membership.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Trusted-partner delivery region pin. Requires a fixed delivery workspace or pinned cluster and the target-managed-workspace entitlement.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Trusted-partner delivery cluster pin. The cluster must belong to the delivery workspace and requires the target-managed-workspace entitlement.", + "x-platform-visibility": "TRUSTED_PARTNER" + }, + "allowed_emails": { + "type": "array", + "items": { + "type": "string", + "maxLength": 254, + "format": "email" + }, + "maxItems": 50, + "description": "Verified customer email allowlist. Empty or omitted means any authenticated customer can redeem the offer." + }, + "field_values": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "nullable": true, + "description": "Pre-fill value for this schema property" + }, + "locked": { + "type": "boolean", + "description": "When true the customer cannot override; submit ignores client value" + } + }, + "required": [ + "value", + "locked" + ] + }, + "description": "Package input pre-fills keyed by input-schema property name. Values are validated against the resolved package version input schema before the offer is created." + }, + "tier": { + "type": "string", + "maxLength": 32, + "description": "Legacy advisory billing tier for non-channel offers. Do not send this with `offer_channel_id`; channel-backed offers use `commercial_mode` and `pricing_request`." + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Offer Channel whose active policy resolves approval, checkout, support, and pricing terms. Requires `product_id`." + }, + "commercial_mode": { + "allOf": [ + { + "$ref": "#/components/schemas/CommercialMode" + }, + { + "description": "Requested customer path for channel policy resolution. This is not settlement authority; the active channel policy decides the final terms." + } + ] + }, + "pricing_request": { + "$ref": "#/components/schemas/OfferPricingRequest" + }, + "notes": { + "type": "string", + "maxLength": 500, + "description": "Seller-private note for operators reviewing or supporting the offer. Not shown to the customer." + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Unix timestamp in seconds after which the offer can no longer be redeemed. Omit for no explicit expiration." + }, + "max_uses": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 10000, + "description": "Maximum number of successful redemptions allowed for this offer. Omit for the default single-use behavior." + }, + "order_ttl_minutes": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 1440, + "description": "Per-redemption order TTL in minutes. Defaults to 120; capped at 1440 (24h)." + } + }, + "required": [ + "package_version_id" + ], + "additionalProperties": false + } + ], + "description": "Provide either `product_id` or `package_version_id`. Product-backed requests may omit `package_version_id`; the server resolves the product’s current package version pin at create time, validates `field_values` against the resolved package version input schema, and stores the resolved package version on the offer." + }, + "OrderDraft": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID" + }, + "offer_id": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer this order draft is redeeming" + }, + "status": { + "$ref": "#/components/schemas/OrderDraftStatus" + }, + "termination_reason": { + "$ref": "#/components/schemas/OrderDraftTerminationReason" + }, + "user_id": { + "type": "string", + "minLength": 1, + "description": "Authenticated customer" + }, + "customer_email": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace selected/created during the workspace phase" + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Cluster allocated during the compute phase" + }, + "cluster_ready": { + "type": "boolean" + }, + "server_joined": { + "type": "boolean" + }, + "payment_completed": { + "type": "boolean" + }, + "current_checkout_session": { + "$ref": "#/components/schemas/CurrentOrderDraftCheckoutSession" + }, + "install_operation_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Operation tracking the spawned install workflow" + }, + "order": { + "$ref": "#/components/schemas/OrderSummary" + }, + "delivery": { + "$ref": "#/components/schemas/OrderDeliverySummary" + }, + "field_values": { + "type": "object", + "additionalProperties": { + "nullable": true + }, + "description": "Customer-supplied configure values, including any pre-fills from the offer. Only returned to the order draft’s own customer; never to other authed callers." + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "ttl_expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "offer_id", + "status", + "cluster_ready", + "server_joined", + "payment_completed", + "created_at", + "updated_at", + "etag", + "ttl_expires_at" + ] + }, + "OrderDraftStatus": { + "type": "string", + "enum": [ + "auth", + "workspace", + "compute", + "compute_bootstrap", + "configure", + "payment", + "install", + "done", + "cleaning_up", + "terminated" + ], + "description": "Wizard phase. Driven by the order draft actor; mirrored on every patch to the row so reactive UIs render one column. `done` and `terminated` are terminal." + }, + "OrderDraftTerminationReason": { + "type": "string", + "enum": [ + "timeout", + "revoked", + "offer_expired", + "install_failed", + "cluster_allocation_failed", + "quota_exceeded" + ], + "description": "Set when status=terminated; explains why the order draft ended." + }, + "CurrentOrderDraftCheckoutSession": { + "type": "object", + "properties": { + "stripe_environment": { + "$ref": "#/components/schemas/StripeEnvironment" + }, + "id": { + "type": "string", + "description": "Stripe Checkout Session ID", + "example": "cs_test_..." + }, + "draft_revision": { + "type": "integer", + "minimum": 0, + "description": "Order draft revision this Checkout Session belongs to" + }, + "url": { + "type": "string", + "format": "uri", + "description": "Stripe-hosted Checkout URL" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "stripe_environment", + "id", + "draft_revision" + ] + }, + "StripeEnvironment": { + "type": "string", + "enum": [ + "live", + "sandbox" + ], + "description": "Stripe payment environment for this Checkout Session." + }, + "OrderSummary": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Order ID" + }, + "status": { + "$ref": "#/components/schemas/OrderStatus" + }, + "stripe_environment": { + "allOf": [ + { + "$ref": "#/components/schemas/StripeEnvironment" + }, + { + "description": "Stripe payment environment for paid Stripe checkout orders." + } + ] + }, + "stripe_checkout_id": { + "type": "string" + }, + "draft_revision": { + "type": "integer", + "minimum": 0 + }, + "cleanup_policy": { + "$ref": "#/components/schemas/OrderCleanupPolicy" + }, + "committed_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "status", + "stripe_checkout_id", + "draft_revision", + "cleanup_policy", + "committed_at" + ] + }, + "OrderStatus": { + "type": "string", + "enum": [ + "delivery_pending", + "delivery_running", + "delivered", + "delivery_failed" + ] + }, + "OrderCleanupPolicy": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "none" + ] + } + }, + "required": [ + "kind" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "temporal_actor_ttl" + ] + }, + "cleanup_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "removable_by": { + "type": "string", + "enum": [ + "platform_policy", + "platform_admin" + ] + }, + "conversion_required": { + "type": "string", + "enum": [ + "paid_order", + "platform_approval" + ] + } + }, + "required": [ + "kind", + "cleanup_at", + "removable_by", + "conversion_required" + ], + "additionalProperties": false + } + ], + "description": "Cleanup policy attached to committed order resources. Demo/test policies are visible so customers and sellers can see when resources will be removed." + }, + "OrderDeliverySummary": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order delivery ID" + }, + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "authorization_kind": { + "type": "string", + "enum": [ + "paid_order", + "non_billable_test_order" + ] + }, + "status": { + "$ref": "#/components/schemas/OrderDeliveryStatus" + }, + "cleanup_policy": { + "$ref": "#/components/schemas/OrderCleanupPolicy" + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "urls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route_key": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "provisioning", + "active", + "not_ready", + "failed" + ], + "description": "Customer-facing install URL routing state." + }, + "error": { + "type": "string" + }, + "last_observed_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "route_key", + "hostname", + "url", + "protocol", + "routing_mode", + "status", + "updated_at" + ] + } + }, + "install_operation_id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Operation tracking the spawned install workflow" + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "completed_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "kind", + "authorization_kind", + "status", + "cleanup_policy", + "urls" + ] + }, + "OrderDeliveryStatus": { + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "failed" + ] + }, + "OrderDraftList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderDraft" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "ClaimOrderDraftBody": { + "type": "object", + "properties": { + "claim_token": { + "type": "string" + } + }, + "required": [ + "claim_token" + ], + "additionalProperties": false + }, + "SelectOrderDraftWorkspaceBody": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "existing" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "kind", + "workspace_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "new" + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + } + }, + "required": [ + "kind" + ], + "additionalProperties": false + } + ] + }, + "SubmitConfigureOrderDraftBody": { + "type": "object", + "properties": { + "field_values": { + "type": "object", + "additionalProperties": { + "nullable": true + }, + "description": "Customer-supplied configure form values, keyed by field name" + } + }, + "required": [ + "field_values" + ], + "additionalProperties": false + }, + "OrderDraftWorkerBootstrap": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Short-lived worker join token (one-time view)." + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Token expiry time (unix seconds)." + }, + "command": { + "type": "string", + "description": "Bash bootstrap command with the token already substituted, ready to run on a worker node." + }, + "cloud_init": { + "type": "string", + "description": "Cloud-init YAML with the token already substituted, ready to use as worker-node user-data." + }, + "artifacts": { + "$ref": "#/components/schemas/WorkerBootstrapArtifacts" + } + }, + "required": [ + "token", + "expires_at", + "command", + "cloud_init" + ] + }, + "WorkerBootstrapArtifacts": { + "type": "object", + "properties": { + "linux": { + "type": "object", + "properties": { + "amd64": { + "$ref": "#/components/schemas/WorkerBootstrapArtifact" + }, + "arm64": { + "$ref": "#/components/schemas/WorkerBootstrapArtifact" + } + } + }, + "windows": { + "type": "object", + "properties": { + "amd64": { + "$ref": "#/components/schemas/WorkerBootstrapArtifact" + }, + "arm64": { + "$ref": "#/components/schemas/WorkerBootstrapArtifact" + } + } + } + }, + "description": "Platform-specific bootstrap artifacts with tokens already substituted. Populated only on create responses." + }, + "WorkerBootstrapArtifact": { + "oneOf": [ + { + "type": "object", + "properties": { + "supported": { + "type": "boolean", + "enum": [ + true + ], + "description": "Whether this platform/architecture artifact is currently supported." + }, + "command": { + "type": "string", + "description": "Bootstrap command with the token already substituted. Reveal-on-create only." + }, + "shell": { + "type": "string", + "enum": [ + "bash", + "powershell" + ], + "description": "Shell expected to execute the bootstrap command or downloaded script." + }, + "download_url": { + "type": "string", + "format": "uri", + "description": "Token-free script URL used by the bootstrap command." + }, + "cloud_init": { + "type": "string", + "description": "Cloud-init YAML with the token already substituted. Reveal-on-create only." + } + }, + "required": [ + "supported" + ] + }, + { + "type": "object", + "properties": { + "supported": { + "type": "boolean", + "enum": [ + false + ], + "description": "Whether this platform/architecture artifact is currently supported. Unsupported entries do not include token-bearing commands." + } + }, + "required": [ + "supported" + ], + "additionalProperties": false + } + ] + }, + "OrderDraftCheckoutSession": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Stripe Checkout Session ID", + "example": "cs_test_..." + }, + "url": { + "type": "string", + "format": "uri", + "description": "Stripe-hosted Checkout URL" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "stripe_environment": { + "$ref": "#/components/schemas/StripeEnvironment" + } + }, + "required": [ + "id", + "url", + "expires_at", + "stripe_environment" + ] + }, + "CheckoutSessionList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CheckoutSession" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "CheckoutSession": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Checkout session ID", + "example": "chk_j572abc..." + }, + "stripe_environment": { + "$ref": "#/components/schemas/StripeEnvironment" + }, + "order_draft_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Parent order draft ID", + "example": "odft_j572abc..." + }, + "order_draft_etag_at_mint": { + "type": "string", + "description": "Parent order draft etag when this checkout session was minted." + }, + "state": { + "$ref": "#/components/schemas/CheckoutSessionStatus" + }, + "url": { + "type": "string", + "format": "uri", + "description": "Stripe-hosted Checkout URL" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "stripe_checkout_session_id": { + "type": "string", + "description": "Stripe Checkout session identifier", + "example": "cs_test_..." + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "stripe_environment", + "order_draft_id", + "order_draft_etag_at_mint", + "state", + "stripe_checkout_session_id", + "created_at", + "updated_at" + ] + }, + "CheckoutSessionStatus": { + "type": "string", + "enum": [ + "open", + "expired", + "payment_failed", + "superseded", + "paid" + ] + }, + "DemoCleanupRemoval": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Order whose demo cleanup was removed." + }, + "delivery_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order delivery whose demo cleanup was removed." + }, + "cleanup_workflow_id": { + "type": "string", + "minLength": 1, + "description": "Previously scheduled Temporal cleanup workflow ID. The workflow will skip after re-reading the removed cleanup policy." + } + }, + "required": [ + "order_id", + "delivery_id", + "cleanup_workflow_id" + ], + "additionalProperties": false, + "x-platform-visibility": "ADMIN" + }, + "RemoveDemoCleanupAfterPlatformApprovalBody": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "minLength": 1, + "maxLength": 1000, + "description": "Platform approval reason for removing non-billable demo cleanup." + } + }, + "required": [ + "reason" + ], + "additionalProperties": false, + "x-platform-visibility": "ADMIN" + }, + "EntitlementList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Entitlement" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + }, + "etag": { + "type": "string" + } + }, + "required": [ + "data", + "has_more", + "next_cursor", + "etag" + ] + }, + "Entitlement": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "feature": { + "type": "object", + "properties": { + "feature_set": { + "type": "string" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "feature_set", + "key", + "name" + ] + }, + "allocation": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bool" + ] + }, + "value": { + "type": "boolean" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "max_count" + ] + }, + "value": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "type", + "value" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unlimited" + ] + }, + "value": { + "nullable": true + } + }, + "required": [ + "type", + "value" + ] + } + ] + } + }, + "required": [ + "workspace_id", + "feature", + "allocation" + ] + }, + "OperationList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Operation" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Operation": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "workspace_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "owner_type": { + "type": "string", + "enum": [ + "install", + "repository_change_request", + "repository", + "workspace", + "machine", + "cluster", + "package" + ], + "description": "Domain entity collection the operation acts on." + }, + "owner_id": { + "type": "string", + "description": "Prefixed ID of the entity this operation acts on. Prefix matches `owner_type` (`ws_`, `mch_`, `clu_`, `pkg_`, `inst_`, `rcr_`, `repo_`)." + }, + "parent_operation_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 53, + "description": "ID of the chained parent operation, when present." + }, + "state": { + "type": "string", + "enum": [ + "RUNNING", + "SUCCEEDED", + "FAILED", + "CANCELLED" + ], + "description": "Lifecycle state. Past-participle terminal states per AIP-216." + }, + "done": { + "type": "boolean", + "description": "True iff state is a terminal value." + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Deep link to the dashboard view of this operation's owning resource when available, otherwise the operation detail page.", + "example": "https://akua.dev/installs/inst_j572abc123def456?tab=operations" + }, + "metadata": { + "$ref": "#/components/schemas/OperationMetadata" + }, + "response": { + "$ref": "#/components/schemas/OperationResponse" + }, + "error": { + "type": "object", + "nullable": true, + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "description": "Populated when `state` is `FAILED` or `CANCELLED`." + }, + "last_error": { + "type": "object", + "nullable": true, + "properties": { + "message": { + "type": "string" + }, + "step_name": { + "type": "string" + } + }, + "required": [ + "message" + ], + "description": "Latest error from any failed step. Populated even mid-flight; cleared when the step succeeds on retry." + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "completed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "steps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OperationStep" + } + } + }, + "required": [ + "id", + "workspace_id", + "organization_id", + "owner_type", + "owner_id", + "parent_operation_id", + "state", + "done", + "html_url", + "metadata", + "response", + "error", + "last_error", + "started_at", + "completed_at" + ] + }, + "OperationMetadata": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "machine.create" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "compute_config_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "instance_type": { + "type": "string" + }, + "managed": { + "type": "boolean" + }, + "request_fingerprint": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "workspace_id", + "cluster_id", + "instance_type", + "managed", + "request_fingerprint" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.delete" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.create" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string" + } + }, + "required": [ + "type", + "workspace_id", + "region_id", + "name" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.suspend" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.resume" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.capabilities.refresh" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.capability.ensure" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "capability": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "cluster_id", + "capability" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.worker_bootstrap.revoke" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "worker_bootstrap_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id", + "worker_bootstrap_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.create" + ] + }, + "idempotency_key": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "type", + "idempotency_key", + "workspace_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.render" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "trigger_commit_sha": { + "type": "string" + } + }, + "required": [ + "type", + "install_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.delete" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "type", + "install_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "preview_hostname.bind_pinned" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ] + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ] + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "install_id", + "render_id", + "protocol", + "routing_mode", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "preview_hostname.bind_floating" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "track": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ] + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ] + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "install_id", + "track", + "render_id", + "protocol", + "routing_mode", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "preview_hostname.delete" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "preview_hostname_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "if_match": { + "type": "string" + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "install_id", + "preview_hostname_id", + "if_match", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "workspace.delete" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "type", + "workspace_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "workspace.subscription.cancel" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "mode": { + "type": "string", + "enum": [ + "period_end" + ] + } + }, + "required": [ + "type", + "workspace_id", + "mode" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "workspace.subdomain.set_name" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63 + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "workspace_id", + "name", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain.create" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "target": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "install_id" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "cluster" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "external" + ] + }, + "endpoint": { + "type": "string", + "format": "uri" + }, + "mtls_secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "endpoint" + ] + } + ] + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ] + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ] + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "workspace_id", + "hostname", + "target", + "protocol", + "routing_mode", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain.update" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "custom_domain_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "target": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "install_id" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "cluster" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "external" + ] + }, + "endpoint": { + "type": "string", + "format": "uri" + }, + "mtls_secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "endpoint" + ] + } + ] + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ] + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ] + }, + "if_match": { + "type": "string" + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "workspace_id", + "custom_domain_id", + "if_match", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain.delete" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "custom_domain_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "if_match": { + "type": "string" + }, + "idempotency_key": { + "type": "string" + } + }, + "required": [ + "type", + "workspace_id", + "custom_domain_id", + "if_match", + "idempotency_key" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cloudflare.private_origin_route.prepare" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "route_intent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "workspace_id", + "cluster_id", + "route_intent_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cloudflare.private_origin_route.release" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "route_intent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "workspace_id", + "route_intent_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "package.create" + ] + }, + "idempotency_key": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + } + }, + "required": [ + "type", + "idempotency_key", + "workspace_id", + "name" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.create" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "parent_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "created_by_kind": { + "type": "string", + "enum": [ + "agent", + "wizard", + "user" + ] + } + }, + "required": [ + "type", + "workspace_id", + "parent_repository_id", + "created_by_kind" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.accept" + ] + }, + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "type", + "repository_change_request_id", + "user_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.reject" + ] + }, + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "user_id": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "type", + "repository_change_request_id", + "user_id", + "reason" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.withdraw" + ] + }, + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "type", + "repository_change_request_id", + "user_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.expire" + ] + }, + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "repository_change_request_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository.delete" + ] + }, + "repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "type", + "repository_id" + ] + } + ] + }, + "OperationResponse": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "machine.create" + ] + }, + "machine_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "provider_id": { + "type": "string" + } + }, + "required": [ + "type", + "machine_id", + "provider_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.delete" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.create" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.suspend" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.resume" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.capabilities.refresh" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.capability.ensure" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "capability": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "cluster_id", + "capability" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cluster.worker_bootstrap.revoke" + ] + }, + "note": { + "type": "string" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.create" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "argo_app_name": { + "type": "string" + }, + "argo_app_namespace": { + "type": "string" + } + }, + "required": [ + "type", + "install_id", + "argo_app_name", + "argo_app_namespace" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.create" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "sandbox_skipped": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "type", + "install_id", + "sandbox_skipped" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.render" + ] + }, + "install_render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "commit_sha": { + "type": "string" + }, + "render_hash": { + "type": "string" + }, + "skipped": { + "type": "boolean" + } + }, + "required": [ + "type", + "install_render_id", + "repository_id", + "render_hash", + "skipped" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "install.delete" + ] + }, + "argo_app_deleted": { + "type": "boolean" + }, + "repo_purged": { + "type": "boolean" + } + }, + "required": [ + "type", + "argo_app_deleted", + "repo_purged" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "preview_hostname.bind_pinned" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "preview_hostname_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "install_id", + "preview_hostname_id", + "hostname" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "preview_hostname.bind_floating" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "preview_hostname_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "install_id", + "preview_hostname_id", + "hostname" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "preview_hostname.delete" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "preview_hostname_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "install_id", + "preview_hostname_id", + "hostname" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "workspace.delete" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "type", + "workspace_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "workspace.subscription.cancel" + ] + }, + "subscription_id": { + "type": "string" + }, + "cancel_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "type", + "subscription_id", + "cancel_at" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "workspace.subdomain.set_name" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "workspace_subdomain_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "fqdn": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "workspace_id", + "workspace_subdomain_id", + "fqdn" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain.create" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "custom_domain_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "workspace_id", + "custom_domain_id", + "hostname" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain.update" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "custom_domain_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "workspace_id", + "custom_domain_id", + "hostname" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain.delete" + ] + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "custom_domain_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + } + }, + "required": [ + "type", + "workspace_id", + "custom_domain_id", + "hostname" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cloudflare.private_origin_route.prepare" + ] + }, + "origin_route_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "origin_route_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cloudflare.private_origin_route.release" + ] + }, + "route_intent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "type", + "route_intent_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "package.create" + ] + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "type", + "package_id", + "package_version_id", + "repository_id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.create" + ] + }, + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "fork_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "type", + "repository_change_request_id", + "fork_repository_id", + "expires_at" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.accept" + ] + }, + "merged_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "triggered_install_render": { + "type": "boolean" + } + }, + "required": [ + "type", + "merged_at", + "triggered_install_render" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.reject" + ] + }, + "rejected_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "type", + "rejected_at" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.withdraw" + ] + }, + "withdrawn_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "type", + "withdrawn_at" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository_change_request.expire" + ] + }, + "expired": { + "type": "boolean" + } + }, + "required": [ + "type", + "expired" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "repository.delete" + ] + }, + "purged_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "type", + "purged_at" + ] + }, + { + "nullable": true + } + ], + "description": "Populated only when `done && state === \"SUCCEEDED\"`. Discriminated by `type`." + }, + "OperationStep": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "User-visible milestone name." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "completed", + "failed", + "skipped" + ], + "description": "Step lifecycle state." + }, + "execution_type": { + "type": "string", + "enum": [ + "system", + "user", + "approval", + "skipped" + ], + "description": "Step execution kind. `user`/`approval` mean the workflow is blocked on a human action. Internal bookkeeping steps are filtered from public responses." + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "completed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "error_message": { + "type": "string", + "nullable": true + }, + "retryable": { + "type": "boolean" + }, + "skippable": { + "type": "boolean" + } + }, + "required": [ + "name", + "status", + "execution_type", + "started_at", + "completed_at", + "error_message", + "retryable", + "skippable" + ] + }, + "DashboardInstallList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardInstall" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "DashboardInstall": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/installs/inst_j572abc123def456" + }, + "name": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "cluster_name": { + "type": "string" + }, + "region_name": { + "type": "string" + }, + "region_icon": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "name", + "workspace_id", + "cluster_id", + "cluster_name", + "region_name", + "region_icon", + "created_at", + "updated_at", + "etag" + ] + }, + "DashboardInstallDetail": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/installs/inst_j572abc123def456" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string", + "nullable": true + }, + "is_standalone": { + "type": "boolean" + }, + "argo_app_namespace": { + "type": "string" + }, + "public_urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstallUrl" + } + }, + "argo_status": { + "$ref": "#/components/schemas/DashboardInstallArgoStatus" + }, + "cluster": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string" + }, + "region": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "type": "string", + "nullable": true + } + }, + "required": [ + "name", + "icon" + ] + } + }, + "required": [ + "id", + "name", + "region" + ] + }, + "product": { + "type": "object", + "nullable": true, + "properties": { + "name": { + "type": "string" + }, + "is_owner": { + "type": "boolean" + } + }, + "required": [ + "name", + "is_owner" + ] + }, + "demo_cleanup": { + "$ref": "#/components/schemas/InstallDemoCleanup" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "workspace_id", + "cluster_id", + "name", + "is_standalone", + "argo_app_namespace", + "public_urls", + "argo_status", + "cluster", + "product", + "created_at", + "updated_at", + "etag" + ] + }, + "InstallUrl": { + "type": "object", + "properties": { + "route_key": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "provisioning", + "active", + "not_ready", + "failed" + ], + "description": "Customer-facing install URL routing state." + }, + "error": { + "type": "string" + }, + "last_observed_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "route_key", + "hostname", + "url", + "protocol", + "routing_mode", + "status", + "updated_at" + ] + }, + "DashboardInstallArgoStatus": { + "type": "object", + "nullable": true, + "properties": { + "status": { + "type": "object", + "properties": { + "health": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "additionalProperties": { + "nullable": true + } + }, + "sync": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "revision": { + "type": "string" + } + }, + "required": [ + "status" + ], + "additionalProperties": { + "nullable": true + } + }, + "operation_state": { + "type": "object", + "properties": { + "phase": { + "type": "string" + } + }, + "required": [ + "phase" + ], + "additionalProperties": { + "nullable": true + } + }, + "resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceStatus" + } + } + }, + "required": [ + "health", + "sync", + "resources" + ], + "additionalProperties": { + "nullable": true + } + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "status", + "updated_at" + ] + }, + "ResourceStatus": { + "type": "object", + "properties": { + "group": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "version": { + "type": "string" + }, + "status": { + "type": "string" + }, + "health": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + }, + "required": [ + "kind", + "name" + ], + "additionalProperties": { + "nullable": true + } + }, + "InstallDemoCleanup": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "scheduled" + ] + }, + "cleanup_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp when the non-billable demo install is scheduled for cleanup." + }, + "removable_by": { + "type": "string", + "enum": [ + "platform_policy", + "platform_admin" + ], + "description": "Authority that may remove the scheduled cleanup policy." + }, + "conversion_required": { + "type": "string", + "enum": [ + "paid_order", + "platform_approval" + ], + "description": "Required approval path before the demo install can continue without cleanup." + }, + "delivery_status": { + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "failed" + ], + "description": "Order delivery status for the install that owns this cleanup policy." + } + }, + "required": [ + "kind", + "cleanup_at", + "removable_by", + "conversion_required", + "delivery_status" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "removed" + ] + }, + "delivery_status": { + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "failed" + ], + "description": "Order delivery status for the demo install whose cleanup was removed." + } + }, + "required": [ + "kind", + "delivery_status" + ], + "additionalProperties": false + } + ], + "description": "Visible cleanup state for non-billable demo installs. Temporal workflow IDs and internal cleanup evidence are intentionally omitted." + }, + "InstallList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Install" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Install": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/installs/inst_j572abc123def456" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "customer_workspace": { + "$ref": "#/components/schemas/InstallCustomerWorkspace" + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "state": { + "type": "string", + "enum": [ + "pending", + "rendering", + "syncing", + "healthy", + "degraded", + "failed", + "deleted" + ], + "description": "Install lifecycle state from the control plane perspective." + }, + "reconciling": { + "type": "boolean" + }, + "urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstallUrl" + } + }, + "demo_cleanup": { + "$ref": "#/components/schemas/InstallDemoCleanup" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "workspace_id", + "customer_workspace", + "cluster_id", + "product_id", + "package_version_id", + "state", + "reconciling", + "urls", + "created_at", + "updated_at", + "etag" + ] + }, + "InstallCustomerWorkspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + } + }, + "required": [ + "id", + "name" + ] + }, + "InstallDomainSettings": { + "type": "object", + "properties": { + "workspace_subdomain": { + "$ref": "#/components/schemas/InstallDomainSettingsWorkspaceSubdomain" + }, + "preview_hostnames": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstallDomainSettingsPreviewHostname" + } + }, + "custom_domains": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstallDomainSettingsCustomDomain" + } + } + }, + "required": [ + "workspace_subdomain", + "preview_hostnames", + "custom_domains" + ] + }, + "InstallDomainSettingsWorkspaceSubdomain": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63 + }, + "fqdn": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "status": { + "type": "string", + "enum": [ + "active", + "propagating", + "reserved" + ] + }, + "name_changed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "fqdn", + "status", + "name_changed_at", + "created_at", + "updated_at", + "etag" + ] + }, + "InstallDomainSettingsPreviewHostname": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + }, + "binding_kind": { + "type": "string", + "enum": [ + "pinned", + "floating" + ] + }, + "track": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 100 + }, + "binding": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "pinned" + ] + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "render_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "floating" + ] + }, + "track": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "track", + "render_id" + ], + "additionalProperties": false + } + ] + }, + "status": { + "type": "string", + "enum": [ + "provisioning", + "active", + "evicted", + "releasing" + ] + }, + "last_seen_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "observed_url": { + "type": "string", + "nullable": true + }, + "error": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "install_id", + "hostname", + "protocol", + "routing_mode", + "binding_kind", + "track", + "binding", + "status", + "last_seen_at", + "observed_url", + "error", + "created_at", + "updated_at", + "etag" + ] + }, + "InstallDomainSettingsCustomDomain": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "target": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "install_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "cluster" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "cluster_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "external" + ] + }, + "endpoint": { + "type": "string", + "format": "uri" + }, + "mtls_secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "endpoint" + ], + "additionalProperties": false + } + ] + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + }, + "target_kind": { + "type": "string", + "enum": [ + "install", + "cluster", + "external" + ] + }, + "cloudflare_custom_hostname_id": { + "type": "string", + "nullable": true + }, + "ssl": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "pending_validation", + "active", + "failed" + ] + }, + "validation_records": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "required": [ + "status" + ] + }, + "status": { + "type": "string", + "enum": [ + "provisioning", + "active", + "failed", + "releasing" + ] + }, + "error": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "hostname", + "target", + "protocol", + "routing_mode", + "target_kind", + "cloudflare_custom_hostname_id", + "ssl", + "status", + "error", + "created_at", + "updated_at", + "etag" + ] + }, + "CreateInstallBody": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "initial_values": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "product_id", + "region_id" + ], + "additionalProperties": false + }, + "InstallRender": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "operation_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 53 + }, + "repository_change_request_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "render_hash": { + "type": "string", + "nullable": true + }, + "commit_sha": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "enum": [ + "running", + "deployed", + "skipped", + "failed" + ] + }, + "message": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "workspace_id", + "install_id", + "render_hash", + "state", + "created_at", + "updated_at" + ] + }, + "CreateInstallRenderBody": { + "type": "object", + "properties": { + "message": { + "type": "string", + "maxLength": 255 + }, + "skip_unchanged": { + "type": "boolean", + "nullable": true, + "default": true + }, + "extra_annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "InstallRenderList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstallRender" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "InstallStatus": { + "type": "object", + "properties": { + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "health": { + "type": "string", + "nullable": true + }, + "sync": { + "type": "string", + "nullable": true + }, + "revision": { + "type": "string", + "nullable": true + }, + "resources": { + "type": "array", + "nullable": true, + "items": { + "$ref": "#/components/schemas/ResourceStatus" + } + }, + "operation_phase": { + "type": "string", + "nullable": true + }, + "updated_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "state": { + "type": "string", + "enum": [ + "pending", + "rendering", + "syncing", + "healthy", + "degraded", + "failed", + "deleted" + ], + "description": "Install lifecycle state from the control plane perspective." + }, + "reconciling": { + "type": "boolean" + } + }, + "required": [ + "install_id", + "health", + "sync", + "revision", + "resources", + "operation_phase", + "updated_at", + "state", + "reconciling" + ] + }, + "PodList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pod" + } + } + }, + "required": [ + "data" + ] + }, + "Pod": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containers": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "name", + "containers" + ] + }, + "PackageList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Package" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Package": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/packages/pkg_j572abc123def456" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + }, + "latest_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "description": { + "type": "string", + "nullable": true + }, + "source": { + "$ref": "#/components/schemas/PackageSource" + }, + "composed_from_sources": { + "type": "array", + "nullable": true, + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "description": "Source provenance used to create this Package (helm URLs, OCI refs, git source details). Only visible in `view=full`." + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "workspace_id", + "name", + "latest_version_id", + "description", + "source", + "created_at" + ] + }, + "PackageSource": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "hosted" + ] + }, + "repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "platform-hosted repository that contains the package source" + } + }, + "required": [ + "kind", + "repository_id" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "oci" + ] + }, + "oci_ref": { + "type": "string", + "description": "OCI reference to the package source (no digest)" + } + }, + "required": [ + "kind", + "oci_ref" + ] + } + ] + }, + "PackageWithVersionsList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageWithVersions" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "PackageWithVersions": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageVersionSummary" + } + } + }, + "required": [ + "id", + "name", + "versions" + ] + }, + "PackageVersionSummary": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "semver": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$" + } + }, + "required": [ + "id", + "semver" + ] + }, + "PackageInventoryList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageInventoryRow" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "PackageInventoryRow": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "source": { + "$ref": "#/components/schemas/PackageSource" + }, + "composed_from_sources": { + "type": "array", + "nullable": true, + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageVersionSummary" + } + }, + "has_more_versions": { + "type": "boolean" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "description", + "source", + "versions", + "has_more_versions", + "created_at", + "etag" + ] + }, + "PackageDetailResponse": { + "type": "object", + "nullable": true, + "properties": { + "package": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "source": { + "$ref": "#/components/schemas/PackageSource" + }, + "composed_from_sources": { + "type": "array", + "nullable": true, + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "description", + "source", + "created_at", + "etag" + ] + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageDetailVersion" + } + } + }, + "required": [ + "package", + "versions" + ] + }, + "PackageDetailVersion": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "semver": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$" + }, + "ref": { + "type": "string" + }, + "input_schema": { + "$ref": "#/components/schemas/PackageVersionInputs" + }, + "compatibility": { + "type": "object", + "properties": { + "clusterTypes": { + "type": "array", + "items": { + "type": "string" + } + }, + "kubernetes": { + "type": "object", + "properties": { + "minVersion": { + "type": "string" + }, + "maxVersion": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "properties": { + "providers": { + "anyOf": [ + { + "type": "string", + "enum": [ + "any" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "regions": { + "anyOf": [ + { + "type": "string", + "enum": [ + "any" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "providers", + "regions" + ] + }, + "kaas": { + "type": "object", + "properties": { + "networkProfile": { + "type": "string", + "enum": [ + "linux_cilium", + "mixed_os_calico" + ] + } + }, + "required": [ + "networkProfile" + ] + } + }, + "required": [ + "clusterTypes", + "kubernetes", + "placement" + ] + }, + "published_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "package_id", + "semver", + "ref", + "input_schema", + "published_at", + "created_at", + "etag" + ] + }, + "PackageVersionInputs": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "PackageVersionList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageVersion" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "PackageVersion": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "semver": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$" + }, + "ref": { + "type": "string" + }, + "input_schema": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "published_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "package_id", + "semver", + "ref", + "input_schema", + "published_at", + "created_at" + ] + }, + "PackageArtifacthubValuesSchema": { + "type": "object", + "properties": { + "values": { + "type": "object", + "additionalProperties": { + "nullable": true + }, + "description": "Parsed chart values object" + }, + "schema": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true + }, + "description": "JSON Schema for the values (null when the values cannot be parsed)" + }, + "values_yaml": { + "type": "string", + "description": "Raw chart values YAML" + } + }, + "required": [ + "values", + "schema", + "values_yaml" + ] + }, + "ImportPackageBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "description": { + "type": "string", + "nullable": true, + "maxLength": 1000 + }, + "oci_ref": { + "type": "string", + "minLength": 1, + "maxLength": 2048, + "pattern": "^oci:\\/\\/", + "description": "OCI reference for the published Akua Package repository. If this registry matches an active workspace registry credential, Akua uses that credential to inspect the artifact." + }, + "version": { + "$ref": "#/components/schemas/CreatePackageVersionBody" + } + }, + "required": [ + "name", + "oci_ref", + "version" + ], + "additionalProperties": false + }, + "CreatePackageVersionBody": { + "type": "object", + "properties": { + "semver": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$", + "example": "1.2.3" + }, + "ref": { + "type": "string", + "minLength": 1, + "maxLength": 512, + "description": "Immutable package content reference. For OCI-backed packages this is normally the digest returned by `akua publish`; Akua verifies it against the published artifact before registering the version." + }, + "input_schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PackageVersionInputs" + }, + { + "description": "JSON Schema exported from the Akua package version. Used to render future install forms; Akua verifies it against the published artifact before registering the version." + } + ] + }, + "compatibility": { + "type": "object", + "properties": { + "clusterTypes": { + "type": "array", + "items": { + "type": "string" + } + }, + "kubernetes": { + "type": "object", + "properties": { + "minVersion": { + "type": "string" + }, + "maxVersion": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "properties": { + "providers": { + "anyOf": [ + { + "type": "string", + "enum": [ + "any" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "regions": { + "anyOf": [ + { + "type": "string", + "enum": [ + "any" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "providers", + "regions" + ] + }, + "kaas": { + "type": "object", + "properties": { + "networkProfile": { + "type": "string", + "enum": [ + "linux_cilium", + "mixed_os_calico" + ] + } + }, + "required": [ + "networkProfile" + ] + } + }, + "required": [ + "clusterTypes", + "kubernetes", + "placement" + ] + } + }, + "required": [ + "semver", + "ref", + "input_schema" + ], + "additionalProperties": false + }, + "PackageOperationEnvelope": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "workspace_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "owner_type": { + "type": "string", + "enum": [ + "install", + "repository_change_request", + "repository", + "workspace", + "machine", + "cluster", + "package" + ], + "description": "Domain entity collection the operation acts on." + }, + "owner_id": { + "type": "string", + "description": "Prefixed ID of the entity this operation acts on. Prefix matches `owner_type` (`ws_`, `mch_`, `clu_`, `pkg_`, `inst_`, `rcr_`, `repo_`)." + }, + "parent_operation_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 53, + "description": "ID of the chained parent operation, when present." + }, + "state": { + "type": "string", + "enum": [ + "RUNNING", + "SUCCEEDED", + "FAILED", + "CANCELLED" + ], + "description": "Lifecycle state. Past-participle terminal states per AIP-216." + }, + "done": { + "type": "boolean", + "description": "True iff state is a terminal value." + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Deep link to the dashboard view of this operation.", + "example": "https://akua.dev/packages/pkg_j572abc123def456?tab=operations" + }, + "metadata": { + "$ref": "#/components/schemas/PackageOperationMetadata" + }, + "response": { + "$ref": "#/components/schemas/PackageOperationResponse" + }, + "error": { + "type": "object", + "nullable": true, + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "description": "Populated when `state` is `FAILED` or `CANCELLED`." + }, + "last_error": { + "type": "object", + "nullable": true, + "properties": { + "message": { + "type": "string" + }, + "step_name": { + "type": "string" + } + }, + "required": [ + "message" + ], + "description": "Latest error from any failed step. Populated even mid-flight; cleared when the step succeeds on retry." + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "completed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "steps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageOperationStep" + } + } + }, + "required": [ + "id", + "workspace_id", + "organization_id", + "owner_type", + "owner_id", + "parent_operation_id", + "state", + "done", + "html_url", + "metadata", + "response", + "error", + "last_error", + "started_at", + "completed_at" + ] + }, + "PackageOperationMetadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "package.create" + ] + }, + "idempotency_key": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + } + }, + "required": [ + "type", + "idempotency_key", + "workspace_id", + "name" + ] + }, + "PackageOperationResponse": { + "type": "object", + "nullable": true, + "properties": { + "type": { + "type": "string", + "enum": [ + "package.create" + ] + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "type", + "package_id", + "package_version_id", + "repository_id" + ], + "description": "Populated only when `done && state === \"SUCCEEDED\"`." + }, + "PackageOperationStep": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "User-visible milestone name." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "completed", + "failed", + "skipped" + ], + "description": "Step lifecycle state." + }, + "execution_type": { + "type": "string", + "enum": [ + "system", + "user", + "approval", + "skipped" + ], + "description": "Step execution kind. `user`/`approval` mean the workflow is blocked on a human action. Internal bookkeeping steps are filtered from public responses." + }, + "started_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "completed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "error_message": { + "type": "string", + "nullable": true + }, + "retryable": { + "type": "boolean" + }, + "skippable": { + "type": "boolean" + } + }, + "required": [ + "name", + "status", + "execution_type", + "started_at", + "completed_at", + "error_message", + "retryable", + "skippable" + ] + }, + "CreatePackageBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "sources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreatePackageHelmSource" + }, + "minItems": 1, + "maxItems": 1 + } + }, + "required": [ + "name", + "sources" + ], + "additionalProperties": false + }, + "CreatePackageHelmSource": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "helm" + ] + }, + "repo_url": { + "type": "string", + "minLength": 1, + "maxLength": 2048, + "pattern": "^oci:\\/\\/" + }, + "chart": { + "type": "string", + "maxLength": 255 + }, + "target_revision": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "path": { + "type": "string", + "maxLength": 2048 + }, + "values": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "kind", + "repo_url", + "target_revision" + ], + "additionalProperties": false + }, + "WorkspaceList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Workspace" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Workspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID", + "example": "ws_j572abc123def456" + }, + "name": { + "type": "string", + "description": "Display name", + "example": "Acme Research" + }, + "slug": { + "type": "string", + "description": "URL-safe workspace slug" + }, + "plan": { + "type": "object", + "properties": { + "tier": { + "type": "string" + }, + "billed_by": { + "type": "string", + "enum": [ + "platform", + "seller" + ] + } + }, + "required": [ + "tier", + "billed_by" + ] + }, + "workspace_class": { + "type": "string", + "enum": [ + "standard", + "platform", + "sandbox" + ] + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug", + "plan", + "workspace_class", + "created_at", + "updated_at", + "etag" + ] + }, + "WorkspaceMemberList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkspaceMember" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "WorkspaceMember": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Workspace member ID", + "example": "wsm_j572abc123def456" + }, + "user_id": { + "type": "string", + "description": "Member user ID", + "example": "usr_j572abc123def456" + }, + "role": { + "type": "string", + "enum": [ + "owner", + "admin", + "member" + ] + }, + "joined_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 join timestamp" + } + }, + "required": [ + "id", + "user_id", + "role", + "joined_at" + ] + }, + "WorkspaceSubscription": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "tier": { + "type": "string" + }, + "status": { + "type": "string" + }, + "cancellation_scheduled": { + "type": "boolean" + }, + "current_period_end": { + "type": "string", + "nullable": true + }, + "billed_by": { + "type": "string", + "enum": [ + "platform", + "seller" + ] + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "workspace_id", + "tier", + "status", + "cancellation_scheduled", + "current_period_end", + "billed_by", + "created_at" + ] + }, + "WorkspaceAccessState": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "status": { + "type": "string", + "enum": [ + "active", + "payment_grace", + "restricted", + "suspended", + "ended", + "reactivating" + ] + }, + "access_version": { + "type": "integer", + "minimum": 0 + }, + "accessible": { + "type": "boolean" + }, + "reason": { + "type": "string", + "nullable": true, + "enum": [ + "payment_grace", + "restricted", + "suspended", + "ended", + "reactivating", + null + ] + }, + "reconciliation_status": { + "type": "string", + "enum": [ + "pending", + "reconciled", + "failed" + ] + }, + "payment_grace_ends_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "restricted_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "suspend_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "ended_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "workspace_id", + "status", + "access_version", + "accessible", + "reason", + "reconciliation_status", + "payment_grace_ends_at", + "restricted_at", + "suspend_at", + "ended_at" + ] + }, + "SubscriptionChangeRequestList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SubscriptionChangeRequest" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "SubscriptionChangeRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "requested_tier": { + "type": "string" + }, + "status": { + "type": "string" + }, + "effective_at": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "workspace_id", + "requested_tier", + "status", + "effective_at", + "created_at" + ] + }, + "CreatedApiToken": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + }, + "token": { + "type": "string", + "description": "The full token. This is shown only once - store it securely.", + "example": "sk_akua_a3b2c4d5e6f7g8h9i0j1k2l3m4n5o6p7" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "token" + ] + }, + "CreateApiTokenRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "description": "Human-readable name for the token", + "example": "My CLI token" + }, + "expires_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds) when the token expires. Omit or pass null for no expiry.", + "example": 1742169600 + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "ApiTokenList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiToken" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "ApiToken": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "example": "My CLI token" + }, + "prefix": { + "type": "string", + "example": "sk_akua_a3b2", + "description": "Short identifier prefix of the full token, for display only." + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "last_used_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds) of last use, or null if never used" + }, + "expires_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds) when the token expires, or null if never" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "prefix", + "created_at", + "last_used_at", + "expires_at" + ] + }, + "RepositoryList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Repository" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Repository": { + "oneOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "name": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "reconciling": { + "type": "boolean" + }, + "purpose": { + "type": "string", + "enum": [ + "deploy" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "last_deploy_sha": { + "type": "string", + "nullable": true + }, + "last_render_hash": { + "type": "string", + "nullable": true + } + }, + "required": [ + "id", + "name", + "workspace_id", + "created_at", + "updated_at", + "etag", + "reconciling", + "purpose", + "cluster_id" + ] + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "name": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "reconciling": { + "type": "boolean" + }, + "purpose": { + "type": "string", + "enum": [ + "package" + ] + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "id", + "name", + "workspace_id", + "created_at", + "updated_at", + "etag", + "reconciling", + "purpose", + "package_id" + ] + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "name": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "reconciling": { + "type": "boolean" + }, + "purpose": { + "type": "string", + "enum": [ + "repository_change_request" + ] + }, + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "id", + "name", + "workspace_id", + "created_at", + "updated_at", + "etag", + "reconciling", + "purpose", + "repository_change_request_id" + ] + } + ] + }, + "GithubInstallationUrl": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "url" + ] + }, + "GithubCreateInstallationUrlBody": { + "type": "object", + "properties": { + "redirect_url": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, + "GithubRepoList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GithubRepo" + } + } + }, + "required": [ + "data" + ] + }, + "GithubRepo": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "name": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "archived": { + "type": "boolean" + }, + "disabled": { + "type": "boolean" + }, + "default_branch": { + "type": "string" + }, + "html_url": { + "type": "string" + }, + "owner": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "login": { + "type": "string" + }, + "type": { + "type": "string" + }, + "avatar_url": { + "type": "string" + }, + "html_url": { + "type": "string" + } + }, + "required": [ + "id", + "login", + "type", + "avatar_url", + "html_url" + ] + } + }, + "required": [ + "id", + "name", + "full_name", + "archived", + "disabled", + "default_branch", + "html_url", + "owner" + ] + }, + "GithubAppInstallationList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GithubAppInstallation" + } + } + }, + "required": [ + "data" + ] + }, + "GithubAppInstallation": { + "type": "object", + "properties": { + "installation_id": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "account": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "User", + "Organization" + ] + }, + "login": { + "type": "string" + }, + "id": { + "type": "number" + } + }, + "required": [ + "type", + "login", + "id" + ] + } + }, + "required": [ + "installation_id", + "workspace_id", + "account" + ] + }, + "GithubWorkflowPrGet": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/GithubWorkflowPr" + } + }, + "required": [ + "data" + ] + }, + "GithubWorkflowPr": { + "type": "object", + "nullable": true, + "properties": { + "pr_id": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "pr_url": { + "type": "string", + "format": "uri" + }, + "status": { + "type": "string", + "enum": [ + "open", + "merged", + "closed", + "draft" + ] + } + }, + "required": [ + "pr_id", + "pr_url", + "status" + ] + }, + "GithubWorkflowRunList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GithubWorkflowRun" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "GithubWorkflowRun": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "custom": { + "type": "object", + "properties": { + "image": { + "type": "string" + }, + "sent_at": { + "type": "number" + } + }, + "required": [ + "image", + "sent_at" + ] + }, + "installation": { + "type": "object", + "properties": { + "id": { + "type": "number" + } + }, + "required": [ + "id" + ] + }, + "workflow_run": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "workflow_id": { + "type": "number" + }, + "run_number": { + "type": "number" + }, + "html_url": { + "type": "string", + "format": "uri" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "run_started_at": { + "type": "string" + }, + "event": { + "type": "string" + }, + "head_branch": { + "type": "string" + }, + "head_sha": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "queued", + "in_progress", + "completed", + "action_required", + "cancelled", + "failure", + "neutral", + "skipped", + "stale", + "success", + "timed_out", + "requested", + "waiting", + "pending" + ] + }, + "conclusion": { + "type": "string", + "nullable": true, + "enum": [ + "success", + "failure", + "cancelled", + "timed_out", + "action_required", + "neutral", + "skipped", + "stale", + "startup_failure", + null + ] + }, + "actor": { + "type": "object", + "properties": { + "login": { + "type": "string" + }, + "id": { + "type": "number" + }, + "avatar_url": { + "type": "string" + }, + "html_url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "login", + "id" + ] + }, + "referenced_workflows": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "sha": { + "type": "string" + }, + "ref": { + "type": "string" + } + }, + "required": [ + "path", + "sha" + ] + } + }, + "head_commit": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "tree_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "message": { + "type": "string" + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "committer": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + } + }, + "required": [ + "name" + ] + } + }, + "required": [ + "id", + "tree_id", + "timestamp", + "message", + "author", + "committer" + ] + } + }, + "required": [ + "id", + "name", + "path", + "workflow_id", + "run_number", + "html_url", + "created_at", + "updated_at", + "run_started_at", + "event", + "head_branch", + "head_sha", + "status", + "conclusion", + "head_commit" + ] + }, + "repository": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "owner": { + "type": "object", + "properties": { + "login": { + "type": "string" + }, + "id": { + "type": "number" + }, + "avatar_url": { + "type": "string", + "format": "uri" + }, + "html_url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "login", + "id", + "avatar_url", + "html_url" + ] + }, + "name": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "html_url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "id", + "owner", + "name", + "full_name", + "html_url" + ] + } + }, + "required": [ + "id", + "installation", + "workflow_run", + "repository" + ] + }, + "GithubPackagePermissions": { + "type": "object", + "properties": { + "has_warning": { + "type": "boolean" + }, + "warning": { + "type": "string" + }, + "fix_url": { + "type": "string" + } + }, + "required": [ + "has_warning" + ] + }, + "GithubCheckPackagePermissionsBody": { + "type": "object", + "properties": { + "repository": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "owner": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "owner", + "name" + ] + }, + "installation_id": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + } + }, + "required": [ + "repository", + "installation_id" + ], + "additionalProperties": false + }, + "GithubWorkflowPrCreated": { + "type": "object", + "properties": { + "pr_id": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "pr_url": { + "type": "string", + "format": "uri" + }, + "status": { + "type": "string", + "enum": [ + "open" + ] + } + }, + "required": [ + "pr_id", + "pr_url", + "status" + ] + }, + "GithubCreateWorkflowPrBody": { + "type": "object", + "properties": { + "repository": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "owner": { + "type": "string" + }, + "name": { + "type": "string" + }, + "default_branch": { + "type": "string" + } + }, + "required": [ + "id", + "owner", + "name", + "default_branch" + ] + }, + "build_settings": { + "type": "object", + "properties": { + "buildContext": { + "type": "string", + "default": "./" + }, + "buildCommand": { + "type": "string" + }, + "startCommand": { + "type": "string" + }, + "installCommand": { + "type": "string" + }, + "buildAptPackages": { + "type": "string" + }, + "runtimeAptPackages": { + "type": "string" + } + } + }, + "installation_id": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + } + }, + "required": [ + "repository", + "build_settings", + "installation_id" + ], + "additionalProperties": false + }, + "GithubVerifyInstallationResponse": { + "type": "object", + "properties": { + "redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_url" + ] + }, + "GithubVerifyInstallationBody": { + "type": "object", + "properties": { + "installation_id": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "code": { + "type": "string", + "minLength": 1 + }, + "state": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "installation_id", + "code", + "state" + ], + "additionalProperties": false + }, + "Secret": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/secrets/sec_j572abc123def456" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "kind": { + "type": "string", + "description": "Secret kind. Current public create values: cloud_provider/hcloud, cloud_provider/aws, cloud_provider/gcp, cloud_provider/azure, oci_registry, cloudflare_api, webhook_signing, generic. cloud_credential is migration-only metadata and cannot be used for new public creates.", + "example": "generic" + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "state": { + "type": "string", + "enum": [ + "active", + "soft_deleted" + ] + }, + "validation": { + "$ref": "#/components/schemas/SecretValidation" + }, + "mime_type": { + "type": "string", + "maxLength": 100 + }, + "version_aliases": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + } + }, + "version_count": { + "type": "integer", + "minimum": 0 + }, + "enabled_version_count": { + "type": "integer", + "minimum": 0 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "deleted_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "purge_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "expire_time": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "workspace_id", + "name", + "kind", + "state", + "validation", + "version_count", + "enabled_version_count", + "created_at", + "updated_at", + "etag" + ] + }, + "SecretValidation": { + "type": "object", + "nullable": true, + "properties": { + "state": { + "type": "string", + "enum": [ + "unspecified", + "valid", + "invalid" + ] + }, + "validated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "error": { + "type": "string" + } + }, + "required": [ + "state", + "validated_at" + ], + "description": "Server-managed validation telemetry. Populated for credential-typed secrets; null otherwise. OUTPUT_ONLY — clients cannot set this on create/update." + }, + "CreateSecretBody": { + "oneOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "cloud_provider/hcloud" + ] + }, + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "cloud_provider/aws" + ] + }, + "value": { + "type": "string", + "minLength": 1 + }, + "aws_access_key_id": { + "type": "string" + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "cloud_provider/gcp" + ] + }, + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "cloud_provider/azure" + ] + }, + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "oci_registry" + ] + }, + "value": { + "type": "string", + "minLength": 1 + }, + "username": { + "type": "string" + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "cloudflare_api" + ] + }, + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "webhook_signing" + ] + }, + "value": { + "type": "string", + "minLength": 16 + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "kind": { + "type": "string", + "enum": [ + "generic" + ] + }, + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "kind", + "value" + ], + "additionalProperties": false + } + ] + }, + "SecretList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Secret" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "UpdateSecretBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string", + "maxLength": 200 + } + }, + "mime_type": { + "type": "string", + "maxLength": 100 + }, + "version_aliases": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + } + } + }, + "additionalProperties": false + }, + "ValidateProviderTokenResult": { + "type": "object", + "properties": { + "valid": { + "type": "boolean", + "description": "Whether the token authenticated successfully." + }, + "error": { + "type": "string", + "description": "Human-readable reason when `valid` is false." + } + }, + "required": [ + "valid" + ] + }, + "ValidateProviderTokenBody": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "hcloud" + ], + "description": "Cloud provider to validate the token against." + }, + "value": { + "type": "string", + "minLength": 1, + "description": "The provider API token to probe. Consumed, never stored." + } + }, + "required": [ + "provider", + "value" + ] + }, + "SecretVersion": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "version_number": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "state": { + "type": "string", + "enum": [ + "enabled", + "disabled", + "destroyed" + ] + }, + "comment": { + "type": "string", + "maxLength": 200 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "destroyed_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "secret_id", + "version_number", + "state", + "created_at", + "etag" + ] + }, + "CreateSecretVersionBody": { + "type": "object", + "properties": { + "value": { + "type": "string", + "minLength": 1 + }, + "comment": { + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "value" + ], + "additionalProperties": false + }, + "SecretVersionList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SecretVersion" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "SecretPlaintext": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + }, + "StripeAccountCreated": { + "type": "object", + "properties": { + "stripe_account_id": { + "type": "string" + } + }, + "required": [ + "stripe_account_id" + ] + }, + "CreateStripeAccountBody": { + "type": "object", + "properties": {}, + "additionalProperties": false + }, + "StripeAccountStatus": { + "type": "object", + "properties": { + "stripe_account_id": { + "type": "string" + }, + "charges_enabled": { + "type": "boolean" + }, + "payouts_enabled": { + "type": "boolean" + } + }, + "required": [ + "stripe_account_id", + "charges_enabled", + "payouts_enabled" + ] + }, + "StripeAccountLinkCreated": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateStripeAccountLinkBody": { + "type": "object", + "properties": { + "return_url": { + "type": "string", + "format": "uri" + }, + "refresh_url": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, + "StripeAccountSessionCreated": { + "type": "object", + "properties": { + "client_secret": { + "type": "string" + } + }, + "required": [ + "client_secret" + ] + }, + "CreateStripeAccountSessionBody": { + "type": "object", + "properties": {}, + "additionalProperties": false + }, + "WorkspaceStripeProducts": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StripeProduct" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + }, + "stripe_account_id": { + "type": "string", + "nullable": true + } + }, + "required": [ + "data", + "has_more", + "next_cursor", + "stripe_account_id" + ] + }, + "StripeProduct": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "type": "string" + } + }, + "prices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StripePrice" + } + } + }, + "required": [ + "id", + "name", + "images", + "prices" + ] + }, + "StripePrice": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "billing_scheme": { + "type": "string" + }, + "nickname": { + "type": "string", + "nullable": true + }, + "unit_amount": { + "type": "number", + "nullable": true + }, + "unit_amount_decimal": { + "type": "string", + "nullable": true + }, + "recurring": { + "type": "object", + "nullable": true, + "properties": { + "interval": { + "type": "string" + }, + "interval_count": { + "type": "number" + }, + "usage_type": { + "type": "string" + } + }, + "required": [ + "interval", + "interval_count", + "usage_type" + ] + } + }, + "required": [ + "id", + "currency", + "billing_scheme", + "nickname", + "unit_amount", + "unit_amount_decimal", + "recurring" + ] + }, + "UpgradeCheckoutCreated": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateUpgradeCheckoutBody": { + "type": "object", + "properties": { + "success_url": { + "type": "string", + "format": "uri" + }, + "cancel_url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "success_url", + "cancel_url" + ], + "additionalProperties": false + }, + "BillingPortalSessionCreated": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateBillingPortalSessionBody": { + "type": "object", + "properties": { + "return_url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "return_url" + ], + "additionalProperties": false + }, + "ClusterList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Cluster" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Cluster": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/clusters/clu_j572abc123def456" + }, + "name": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "state": { + "type": "string", + "enum": [ + "pending", + "provisioning", + "active", + "suspended", + "deleting" + ], + "description": "Cluster lifecycle state in canonical lowercase, past-participle naming." + }, + "provider": { + "type": "string", + "enum": [ + "managed_kaas", + "imported_byoc" + ], + "description": "Cluster control-plane family: managed (`managed_kaas`) vs imported self-managed (`imported_byoc`)." + }, + "reconciling": { + "type": "boolean" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "name", + "workspace_id", + "state", + "provider", + "reconciling", + "created_at", + "updated_at", + "etag" + ] + }, + "DashboardClusterList": { + "type": "object", + "properties": { + "clusters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardCluster" + } + }, + "regions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardClusterRegion" + } + } + }, + "required": [ + "clusters", + "regions" + ] + }, + "DashboardCluster": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/clusters/clu_j572abc123def456" + }, + "name": { + "type": "string" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "region": { + "$ref": "#/components/schemas/DashboardClusterRegion" + }, + "kaas": { + "$ref": "#/components/schemas/ClusterKaas" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "product_count": { + "type": "integer", + "minimum": 0 + }, + "installs_count": { + "type": "integer", + "minimum": 0 + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "name", + "workspace_id", + "region_id", + "region", + "kaas", + "created_at", + "updated_at", + "product_count", + "installs_count", + "etag" + ] + }, + "DashboardClusterRegion": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string" + }, + "icon": { + "type": "string", + "nullable": true + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "name", + "icon", + "workspace_id", + "created_at" + ] + }, + "ClusterKaas": { + "type": "object", + "nullable": true, + "properties": { + "namespace": { + "type": "string" + }, + "version": { + "type": "string" + }, + "network_profile": { + "type": "string", + "enum": [ + "linux_cilium", + "mixed_os_calico" + ], + "default": "linux_cilium", + "description": "Immutable networking profile for managed KaaS clusters. Defaults to `linux_cilium`; Windows workers require `mixed_os_calico`." + }, + "status": { + "type": "string", + "enum": [ + "PROVISIONING", + "RUNNING", + "RECONCILING", + "SUSPENDING", + "SUSPENDED", + "RESUMING", + "DELETING", + "ERROR", + "DEGRADED" + ] + }, + "status_message": { + "type": "string", + "nullable": true + }, + "suspended_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "suspended_by": { + "type": "string", + "nullable": true + } + }, + "required": [ + "namespace", + "version", + "network_profile", + "status", + "status_message", + "suspended_at", + "suspended_by" + ] + }, + "ClusterCapabilities": { + "type": "object", + "properties": { + "api_groups": { + "type": "array", + "items": { + "type": "string" + } + }, + "storage_classes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "provisioner": { + "type": "string" + }, + "is_default": { + "type": "boolean" + }, + "reclaim_policy": { + "type": "string" + }, + "volume_binding_mode": { + "type": "string" + } + }, + "required": [ + "name", + "provisioner", + "is_default", + "reclaim_policy", + "volume_binding_mode" + ] + } + }, + "gateway_classes": { + "type": "array", + "items": { + "type": "string" + } + }, + "gateways": { + "type": "array", + "items": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "name": { + "type": "string" + }, + "gateway_class_name": { + "type": "string" + }, + "listeners": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "protocol": { + "type": "string" + }, + "port": { + "type": "number" + }, + "hostname": { + "type": "string" + } + }, + "required": [ + "name", + "protocol", + "port" + ] + } + }, + "addresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "value" + ] + } + }, + "status": { + "type": "string", + "enum": [ + "Ready", + "Accepted", + "Pending", + "Error", + "Unknown" + ] + }, + "status_message": { + "type": "string" + } + }, + "required": [ + "namespace", + "name", + "gateway_class_name", + "listeners" + ] + } + }, + "default_gateway": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "namespace", + "name" + ] + }, + "ingress_classes": { + "type": "array", + "items": { + "type": "string" + } + }, + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "ready": { + "type": "boolean" + }, + "worker_capacity": { + "type": "boolean" + }, + "status_message": { + "type": "string" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "created_at": { + "type": "string" + }, + "version": { + "type": "string" + }, + "cpu_capacity": { + "type": "string" + }, + "memory_capacity": { + "type": "string" + }, + "os_image": { + "type": "string" + }, + "operating_system": { + "type": "string" + }, + "architecture": { + "type": "string" + } + }, + "required": [ + "name", + "roles", + "version", + "cpu_capacity", + "memory_capacity", + "os_image", + "architecture" + ] + } + } + }, + "required": [ + "api_groups", + "storage_classes", + "gateway_classes", + "gateways", + "ingress_classes", + "nodes" + ] + }, + "Kubeconfig": { + "type": "object", + "properties": { + "kubeconfig": { + "type": "string" + } + }, + "required": [ + "kubeconfig" + ] + }, + "ExecResult": { + "type": "object", + "properties": { + "output": { + "type": "string" + }, + "exit_code": { + "type": "integer" + }, + "duration_ms": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "output", + "exit_code", + "duration_ms" + ] + }, + "ExecBody": { + "type": "object", + "properties": { + "namespace": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "pod": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "container": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "namespace", + "pod", + "command" + ], + "additionalProperties": false + }, + "WorkerBootstrap": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "status": { + "type": "string", + "enum": [ + "active", + "revoked", + "expired" + ], + "description": "Lifecycle state for a one-time worker bootstrap token." + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + }, + "token": { + "type": "string", + "description": "One-time-view bearer token. Populated only on the create response; never returned on subsequent GET/LIST/:revoke reads." + }, + "command": { + "type": "string", + "description": "Bash bootstrap command with the token already substituted, ready to run on a worker node. Reveal-on-create only." + }, + "cloud_init": { + "type": "string", + "description": "Cloud-init YAML with the token already substituted, ready to use as worker-node user-data. Reveal-on-create only." + }, + "artifacts": { + "$ref": "#/components/schemas/WorkerBootstrapArtifacts" + } + }, + "required": [ + "id", + "cluster_id", + "status", + "created_at", + "updated_at", + "etag" + ] + }, + "WorkerBootstrapList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkerBootstrap" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AdminStatus": { + "type": "object", + "properties": { + "is_admin": { + "type": "boolean", + "description": "Whether the authenticated user has platform administrator access." + } + }, + "required": [ + "is_admin" + ], + "x-platform-visibility": "ADMIN" + }, + "DashboardCounts": { + "type": "object", + "properties": { + "install_count": { + "type": "integer", + "minimum": 0 + }, + "product_count": { + "type": "integer", + "minimum": 0 + }, + "cluster_count": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "install_count", + "product_count", + "cluster_count" + ], + "x-platform-visibility": "INTERNAL" + }, + "OrganizationList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Organization" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string", + "example": "Code Zero" + }, + "slug": { + "type": "string", + "nullable": true, + "example": "code-zero" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug", + "created_at", + "updated_at", + "etag" + ] + }, + "OrganizationCreateRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 2, + "maxLength": 50, + "pattern": "^[\\p{L}\\p{N}](?:[\\p{L}\\p{N}\\s\\-'&.]*[\\p{L}\\p{N}])?$/u" + }, + "slug": { + "type": "string", + "minLength": 3, + "maxLength": 39, + "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "OrganizationOk": { + "type": "object", + "properties": { + "ok": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "ok" + ] + }, + "OrganizationUpdateRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 2, + "maxLength": 50, + "pattern": "^[\\p{L}\\p{N}](?:[\\p{L}\\p{N}\\s\\-'&.]*[\\p{L}\\p{N}])?$/u" + }, + "slug": { + "type": "string", + "minLength": 3, + "maxLength": 39, + "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$" + } + }, + "additionalProperties": false + }, + "OrganizationMemberList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationMember" + } + } + }, + "required": [ + "data" + ] + }, + "OrganizationMember": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "user_abc123", + "description": "BetterAuth user ID of the member" + }, + "role": { + "type": "string", + "enum": [ + "owner", + "admin", + "member" + ], + "description": "Membership role in the organization", + "example": "admin" + }, + "joined_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "user_id", + "role", + "joined_at", + "updated_at", + "etag" + ] + }, + "OrganizationAddMemberRequest": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "user_abc123", + "description": "BetterAuth user ID of the user to add" + }, + "role": { + "type": "string", + "enum": [ + "owner", + "admin", + "member" + ], + "default": "member", + "description": "Membership role in the organization" + } + }, + "required": [ + "user_id" + ], + "additionalProperties": false + }, + "OrganizationUpdateMemberRoleRequest": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "owner", + "admin", + "member" + ], + "description": "Membership role in the organization" + } + }, + "required": [ + "role" + ], + "additionalProperties": false + }, + "ManagedWorkspaceList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManagedWorkspace" + } + } + }, + "required": [ + "data" + ] + }, + "ManagedWorkspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "example": "My Workspace" + }, + "icon": { + "type": "string", + "nullable": true, + "example": null + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "name", + "icon", + "created_at" + ] + }, + "NotificationList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Notification" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Notification": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "type": { + "type": "string", + "example": "machine_expiry" + }, + "resource_type": { + "type": "string", + "example": "machine" + }, + "resource_id": { + "type": "string" + }, + "title": { + "type": "string", + "nullable": true + }, + "body": { + "type": "string", + "nullable": true + }, + "severity": { + "type": "string", + "nullable": true, + "enum": [ + "info", + "warning", + "critical", + null + ], + "description": "Severity level surfaced to UI indicators." + }, + "context": { + "type": "object", + "nullable": true, + "additionalProperties": { + "type": "string" + } + }, + "read_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds) when read, null if unread" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "type", + "resource_type", + "resource_id", + "title", + "body", + "severity", + "context", + "read_at", + "created_at" + ] + }, + "UnreadCount": { + "type": "object", + "properties": { + "count": { + "type": "number" + } + }, + "required": [ + "count" + ] + }, + "QuotaInfoList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QuotaInfo" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "QuotaInfo": { + "type": "object", + "properties": { + "metric": { + "type": "string", + "example": "compute/machines", + "description": "Metric: service/resource" + }, + "type": { + "type": "string", + "enum": [ + "allocation", + "rate", + "concurrency" + ], + "description": "Allocation = max owned, rate = max per time window, concurrency = max in-flight.", + "example": "allocation" + }, + "display_name": { + "type": "string", + "example": "Compute machines" + }, + "unit": { + "type": "string", + "enum": [ + "count", + "cores", + "bytes", + "seconds", + "count/day", + "count/minute", + "cents/day" + ], + "description": "Unit the limit/usage numbers are measured in.", + "example": "count" + }, + "limit": { + "type": "number", + "example": 1 + }, + "usage": { + "type": "number", + "example": 0 + }, + "remaining": { + "type": "number", + "example": 1 + }, + "resets_at": { + "type": "integer", + "minimum": 0, + "description": "For rate quotas: Unix timestamp (seconds) reset time" + } + }, + "required": [ + "metric", + "type", + "display_name", + "unit", + "limit", + "usage", + "remaining" + ] + }, + "RegionList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Region" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "Region": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string", + "example": "us-east-1" + }, + "icon": { + "type": "string", + "nullable": true, + "description": "Icon URL" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "name", + "icon", + "workspace_id", + "created_at" + ] + }, + "DashboardRegionList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardRegion" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "DashboardRegion": { + "allOf": [ + { + "$ref": "#/components/schemas/Region" + }, + { + "type": "object", + "properties": { + "cluster_pool_health": { + "$ref": "#/components/schemas/ClusterPoolHealth" + } + }, + "required": [ + "cluster_pool_health" + ] + } + ] + }, + "ClusterPoolHealth": { + "type": "object", + "properties": { + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "target_size": { + "type": "number" + }, + "enabled": { + "type": "boolean" + }, + "available": { + "type": "number" + }, + "provisioning": { + "type": "number" + }, + "allocation_requests": { + "type": "number" + }, + "allocated_last_24h": { + "type": "number" + }, + "deleted_last_24h": { + "type": "number" + }, + "failed_last_24h": { + "type": "number" + }, + "last_refill_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "last_error": { + "type": "string" + } + }, + "required": [ + "region_id", + "target_size", + "enabled", + "available", + "provisioning", + "allocation_requests", + "allocated_last_24h", + "deleted_last_24h", + "failed_last_24h" + ] + }, + "RegistryCredentialList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegistryCredential" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "RegistryCredential": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "name": { + "type": "string", + "example": "GitHub Container Registry" + }, + "registry_url": { + "type": "string", + "example": "ghcr.io" + }, + "type": { + "type": "string", + "enum": [ + "basic", + "token", + "oauth" + ], + "description": "Authentication scheme used to talk to the upstream registry." + }, + "is_active": { + "type": "boolean", + "description": "Whether the credential is active" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "last_used_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds), null if never used" + } + }, + "required": [ + "id", + "name", + "registry_url", + "type", + "is_active", + "created_at", + "last_used_at" + ] + }, + "RegistryStats": { + "type": "object", + "properties": { + "total_pulls": { + "type": "number" + }, + "successful_pulls": { + "type": "number" + }, + "failed_pulls": { + "type": "number" + }, + "success_rate": { + "type": "number" + }, + "auth_successes": { + "type": "number" + }, + "auth_failures": { + "type": "number" + }, + "by_registry": { + "type": "array", + "items": { + "type": "object", + "properties": { + "registry_url": { + "type": "string" + }, + "pulls": { + "type": "number" + }, + "failures": { + "type": "number" + } + }, + "required": [ + "registry_url", + "pulls", + "failures" + ] + } + }, + "latency": { + "type": "object", + "properties": { + "avg": { + "type": "number", + "nullable": true + }, + "p95": { + "type": "number", + "nullable": true + } + }, + "required": [ + "avg", + "p95" + ] + } + }, + "required": [ + "total_pulls", + "successful_pulls", + "failed_pulls", + "success_rate", + "auth_successes", + "auth_failures", + "by_registry", + "latency" + ] + }, + "RegistryActivityResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegistryActivityBucket" + } + } + }, + "required": [ + "data" + ] + }, + "RegistryActivityBucket": { + "type": "object", + "properties": { + "timestamp": { + "type": "number", + "description": "Unix timestamp in milliseconds." + }, + "success": { + "type": "number" + }, + "failed": { + "type": "number" + } + }, + "required": [ + "timestamp", + "success", + "failed" + ] + }, + "RegistryAuditLogList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegistryAuditLog" + } + } + }, + "required": [ + "data" + ] + }, + "RegistryAuditLog": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "timestamp": { + "type": "number", + "description": "Unix timestamp in milliseconds." + }, + "operation": { + "type": "string", + "enum": [ + "pull_manifest", + "pull_blob", + "pull_failed", + "auth_success", + "auth_failed" + ] + }, + "registry_url": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "reference": { + "type": "string", + "nullable": true + }, + "success": { + "type": "boolean" + }, + "install_name": { + "type": "string", + "nullable": true + } + }, + "required": [ + "id", + "timestamp", + "operation", + "registry_url", + "repository", + "reference", + "success", + "install_name" + ] + }, + "RegistryErrorList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegistryError" + } + } + }, + "required": [ + "data" + ] + }, + "RegistryError": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "count": { + "type": "number" + } + }, + "required": [ + "message", + "count" + ] + }, + "CreateRepositoryChangeRequestResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/repository-change-requests/rcr_j572abc123def456" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "parent_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "fork_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "state": { + "type": "string", + "enum": [ + "AWAITING_CHANGES", + "VALIDATING", + "READY", + "ACCEPTING", + "ACCEPTED", + "REJECTED", + "WITHDRAWN", + "EXPIRED", + "FAILED" + ], + "description": "Repository change request lifecycle state" + }, + "change_type": { + "type": "string", + "enum": [ + "manifest_patch", + "inputs_change", + "package_change", + "unknown" + ] + }, + "created_by_type": { + "type": "string", + "enum": [ + "user", + "wizard", + "agent" + ] + }, + "created_by_id": { + "type": "string" + }, + "remediation_evidence": { + "type": "object", + "nullable": true, + "properties": { + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "likely_fix": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "resource_refs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "resource", + "id" + ], + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 20 + } + }, + "required": [ + "summary", + "likely_fix", + "resource_refs" + ], + "additionalProperties": false + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "rejection_reason": { + "type": "string", + "nullable": true + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "workspace_id", + "parent_repository_id", + "fork_repository_id", + "state", + "change_type", + "created_by_type", + "created_by_id", + "remediation_evidence", + "created_at", + "updated_at", + "expires_at", + "rejection_reason", + "etag" + ] + }, + "CreateRepositoryChangeRequestBody": { + "oneOf": [ + { + "type": "object", + "properties": { + "parent_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Repository that will receive the accepted change request." + }, + "expires_at_seconds": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Seconds until the repository change request expires." + }, + "kind": { + "type": "string", + "enum": [ + "user" + ] + } + }, + "required": [ + "parent_repository_id", + "kind" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "parent_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Repository that will receive the accepted change request." + }, + "expires_at_seconds": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Seconds until the repository change request expires." + }, + "kind": { + "type": "string", + "enum": [ + "wizard" + ] + } + }, + "required": [ + "parent_repository_id", + "kind" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "parent_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Repository that will receive the accepted change request." + }, + "expires_at_seconds": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Seconds until the repository change request expires." + }, + "kind": { + "type": "string", + "enum": [ + "agent" + ], + "description": "Agent actor creating the change request." + }, + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Agent that found the likely source or configuration fix." + }, + "remediation_evidence": { + "type": "object", + "properties": { + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "likely_fix": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "resource_refs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "resource", + "id" + ], + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 20 + } + }, + "required": [ + "summary", + "likely_fix", + "resource_refs" + ], + "additionalProperties": false, + "description": "Evidence that the agent found a likely source or configuration fix before opening the change request." + } + }, + "required": [ + "parent_repository_id", + "kind", + "agent_id", + "remediation_evidence" + ], + "additionalProperties": false + } + ] + }, + "CreateRepositoryChangeRequestTokenResponse": { + "type": "object", + "properties": { + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "fork_remote_url": { + "type": "string", + "format": "uri" + }, + "fork_write_token": { + "type": "string" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "repository_change_request_id", + "fork_remote_url", + "fork_write_token", + "expires_at" + ] + }, + "CreateRepositoryChangeRequestTokenBody": { + "type": "object", + "properties": { + "scope": { + "type": "string", + "enum": [ + "read", + "write" + ], + "default": "write" + }, + "expires_in_seconds": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 3600, + "description": "Seconds until the fork write token expires. Maximum is one hour." + } + }, + "additionalProperties": false + }, + "RepositoryChangeRequestList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryChangeRequest" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "RepositoryChangeRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "html_url": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "description": "Absolute dashboard URL for this resource. OUTPUT_ONLY.", + "example": "https://akua.dev/repository-change-requests/rcr_j572abc123def456" + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "parent_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "fork_repository_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "state": { + "type": "string", + "enum": [ + "AWAITING_CHANGES", + "VALIDATING", + "READY", + "ACCEPTING", + "ACCEPTED", + "REJECTED", + "WITHDRAWN", + "EXPIRED", + "FAILED" + ], + "description": "Repository change request lifecycle state" + }, + "change_type": { + "type": "string", + "enum": [ + "manifest_patch", + "inputs_change", + "package_change", + "unknown" + ] + }, + "created_by_type": { + "type": "string", + "enum": [ + "user", + "wizard", + "agent" + ] + }, + "created_by_id": { + "type": "string" + }, + "remediation_evidence": { + "type": "object", + "nullable": true, + "properties": { + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "likely_fix": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "resource_refs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "resource", + "id" + ], + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 20 + } + }, + "required": [ + "summary", + "likely_fix", + "resource_refs" + ], + "additionalProperties": false + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "expires_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "rejection_reason": { + "type": "string", + "nullable": true + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "html_url", + "workspace_id", + "parent_repository_id", + "fork_repository_id", + "state", + "change_type", + "created_by_type", + "created_by_id", + "remediation_evidence", + "created_at", + "updated_at", + "expires_at", + "rejection_reason", + "etag" + ] + }, + "AcceptRepositoryChangeRequestResponse": { + "type": "object", + "properties": { + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "operation_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "accepted_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "repository_change_request_id", + "operation_id", + "accepted_at" + ] + }, + "RejectRepositoryChangeRequestResponse": { + "type": "object", + "properties": { + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "rejected_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "repository_change_request_id", + "rejected_at" + ] + }, + "RejectRepositoryChangeRequestBody": { + "type": "object", + "properties": { + "rejection_reason": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "Reason shown in audit logs and review UI." + } + }, + "required": [ + "rejection_reason" + ], + "additionalProperties": false + }, + "WithdrawRepositoryChangeRequestResponse": { + "type": "object", + "properties": { + "repository_change_request_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "withdrawn_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "repository_change_request_id", + "withdrawn_at" + ] + }, + "Agent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "instructions": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "ENABLED", + "ARCHIVED" + ] + }, + "origin": { + "type": "string", + "enum": [ + "PLATFORM", + "USER", + "SYSTEM" + ] + }, + "capabilities": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "CHAT", + "CODING", + "AMBIENT" + ] + } + }, + "ambient": { + "$ref": "#/components/schemas/AgentAmbientConfig" + }, + "model_policy": { + "$ref": "#/components/schemas/AgentModelPolicy" + }, + "created_by": { + "type": "string" + }, + "usage_summary": { + "$ref": "#/components/schemas/AgentUsageSummary" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "organization_id", + "name", + "description", + "instructions", + "state", + "origin", + "capabilities", + "ambient", + "model_policy", + "created_by", + "usage_summary", + "created_at", + "updated_at", + "etag" + ] + }, + "AgentAmbientConfig": { + "type": "object", + "nullable": true, + "properties": { + "enabled": { + "type": "boolean" + }, + "policy": { + "$ref": "#/components/schemas/AgentAmbientPolicy" + }, + "triggers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentAmbientTrigger" + }, + "maxItems": 50 + } + }, + "required": [ + "enabled", + "triggers" + ] + }, + "AgentAmbientPolicy": { + "type": "object", + "properties": { + "remediation_mode": { + "type": "string", + "enum": [ + "READ_ONLY", + "APPROVAL_GATED" + ] + }, + "allowed_resource_scopes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentAmbientResourceScope" + }, + "maxItems": 100 + }, + "max_spend_cents_per_trigger": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "remediation_mode", + "allowed_resource_scopes" + ] + }, + "AgentAmbientResourceScope": { + "type": "object", + "properties": { + "type": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "type" + ] + }, + "AgentAmbientTrigger": { + "type": "object", + "properties": { + "trigger_id": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "type": { + "type": "string", + "enum": [ + "INSTALL_STATE", + "CLUSTER_DEGRADATION", + "SECURITY_FINDING", + "QUOTA_PRESSURE", + "COST_ANOMALY", + "MANUAL_TEST" + ] + }, + "state": { + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "severity_min": { + "type": "string", + "enum": [ + "LOW", + "MEDIUM", + "HIGH", + "CRITICAL" + ] + }, + "runtime_hint": { + "type": "string", + "enum": [ + "AUTO", + "CODE_MODE", + "RETAINED_RUNTIME" + ] + }, + "cooldown_seconds": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "relationship_scope": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "WORKSPACE" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "SELLER_CUSTOMER" + ] + }, + "seller_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "customer_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "support_relationship_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "type", + "seller_workspace_id", + "customer_workspace_id" + ] + } + ] + }, + "resource_filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "type", + "id" + ] + }, + "maxItems": 50 + }, + "quiet_hours": { + "type": "object", + "properties": { + "timezone": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "start": { + "type": "string", + "pattern": "^\\d{2}:\\d{2}$" + }, + "end": { + "type": "string", + "pattern": "^\\d{2}:\\d{2}$" + } + }, + "required": [ + "timezone", + "start", + "end" + ] + } + }, + "required": [ + "trigger_id", + "type", + "state", + "runtime_hint" + ] + }, + "AgentModelPolicy": { + "type": "object", + "properties": { + "default_model": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "billing_mode": { + "type": "string", + "enum": [ + "PLATFORM_SUBSCRIPTION", + "PLATFORM_API", + "WORKSPACE_BYOK" + ] + }, + "credential_secret_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "allowed_models": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "minItems": 1, + "maxItems": 50 + }, + "severity_model_overrides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "severity": { + "type": "string", + "enum": [ + "LOW", + "MEDIUM", + "HIGH", + "CRITICAL" + ] + }, + "model": { + "type": "string", + "minLength": 1, + "maxLength": 120 + } + }, + "required": [ + "severity", + "model" + ] + }, + "maxItems": 4 + }, + "max_budget_cents": { + "type": "integer", + "minimum": 0 + }, + "budget_period": { + "type": "string", + "enum": [ + "DAY", + "WEEK", + "MONTH" + ] + }, + "max_turn_budget_cents": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "default_model", + "billing_mode", + "credential_secret_id", + "allowed_models" + ] + }, + "AgentUsageSummary": { + "type": "object", + "properties": { + "provider_cost_cents": { + "type": "integer", + "minimum": 0 + }, + "provider_token_count": { + "type": "integer", + "minimum": 0 + }, + "runtime_compute_seconds": { + "type": "number", + "minimum": 0 + }, + "runtime_storage_gb_hours": { + "type": "number", + "minimum": 0 + }, + "mcp_call_count": { + "type": "integer", + "minimum": 0 + }, + "api_call_count": { + "type": "integer", + "minimum": 0 + }, + "ambient_trigger_count": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "provider_cost_cents", + "provider_token_count", + "runtime_compute_seconds", + "runtime_storage_gb_hours", + "mcp_call_count", + "api_call_count", + "ambient_trigger_count" + ] + }, + "AgentList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Agent" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AgentSkillList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentSkill" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AgentSkill": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "PUBLISHED", + "ARCHIVED" + ] + }, + "required_grants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string" + }, + "actions": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "resource", + "actions" + ] + } + }, + "supported_capabilities": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "CHAT", + "CODING", + "AMBIENT" + ] + } + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "version", + "description", + "state", + "required_grants", + "supported_capabilities", + "created_at", + "updated_at", + "etag" + ] + }, + "AgentTemplateList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentTemplate" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AgentTemplate": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "instructions": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "PUBLISHED" + ] + }, + "capabilities": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "CHAT", + "CODING", + "AMBIENT" + ] + } + }, + "ambient": { + "$ref": "#/components/schemas/AgentAmbientConfig" + }, + "trigger_filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentTemplateTriggerFilter" + } + }, + "model_policy": { + "$ref": "#/components/schemas/AgentModelPolicy" + }, + "runtime_policy": { + "$ref": "#/components/schemas/AgentRuntimePolicy" + }, + "remediation_policy": { + "$ref": "#/components/schemas/AgentTemplateRemediationPolicy" + }, + "grants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string" + }, + "actions": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "resource", + "actions" + ] + } + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "description", + "instructions", + "state", + "capabilities", + "ambient", + "trigger_filters", + "model_policy", + "runtime_policy", + "remediation_policy", + "grants", + "created_at", + "updated_at", + "etag" + ] + }, + "AgentTemplateTriggerFilter": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "INSTALL_STATE", + "CLUSTER_DEGRADATION", + "SECURITY_FINDING", + "QUOTA_PRESSURE", + "COST_ANOMALY", + "MANUAL_TEST" + ] + }, + "resource_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "states": { + "type": "array", + "items": { + "type": "string" + } + }, + "min_severity": { + "type": "string", + "enum": [ + "LOW", + "MEDIUM", + "HIGH", + "CRITICAL" + ] + } + }, + "required": [ + "type", + "resource_types", + "states" + ] + }, + "AgentRuntimePolicy": { + "type": "object", + "properties": { + "execution_environment": { + "type": "string", + "enum": [ + "CODE_MODE_FIRST", + "RETAINED_RUNTIME_ALLOWED", + "NO_RETAINED_RUNTIME" + ] + }, + "filesystem": { + "type": "string" + }, + "shell": { + "type": "string" + }, + "browser": { + "type": "string" + } + }, + "required": [ + "execution_environment", + "filesystem", + "shell", + "browser" + ] + }, + "AgentTemplateRemediationPolicy": { + "type": "object", + "nullable": true, + "properties": { + "repository_change_request": { + "$ref": "#/components/schemas/AgentTemplateRepositoryChangeRequestRemediationPolicy" + } + }, + "required": [ + "repository_change_request" + ] + }, + "AgentTemplateRepositoryChangeRequestRemediationPolicy": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "LIKELY_SOURCE_OR_CONFIG_FIX_ONLY" + ] + }, + "evidence_required": { + "type": "boolean" + }, + "allowed_actions": { + "type": "array", + "items": { + "type": "string" + } + }, + "blocked_actions": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "evidence_required", + "allowed_actions", + "blocked_actions" + ] + }, + "AgentPreference": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "user_id": { + "type": "string" + }, + "communication_profile": { + "type": "string", + "enum": [ + "BEGINNER", + "INTERMEDIATE", + "ADVANCED", + "EXPERT", + "ADAPTIVE" + ] + }, + "learning_mode_enabled": { + "type": "boolean" + }, + "seen_concepts": { + "type": "array", + "items": { + "type": "string" + } + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "user_id", + "communication_profile", + "learning_mode_enabled", + "seen_concepts", + "created_at", + "updated_at", + "etag" + ] + }, + "SandboxOperationsSummary": { + "type": "object", + "properties": { + "active_sandbox_count": { + "type": "integer", + "minimum": 0 + }, + "idle_retained_filesystem_count": { + "type": "integer", + "minimum": 0 + }, + "retained_filesystem_age_ms": { + "type": "number", + "minimum": 0 + }, + "estimated_retained_filesystem_gb_hours": { + "type": "number", + "minimum": 0 + }, + "stuck_sandbox_count_by_state": { + "type": "array", + "items": { + "type": "object", + "properties": { + "state": { + "type": "string", + "enum": [ + "CREATING", + "STARTING", + "ACTIVE", + "STOPPING", + "STOPPED", + "DELETING", + "DELETED", + "FAILED" + ] + }, + "count": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "state", + "count" + ] + } + }, + "average_cold_start_latency_ms": { + "type": "number", + "nullable": true, + "minimum": 0 + }, + "average_resume_latency_ms": { + "type": "number", + "nullable": true, + "minimum": 0 + } + }, + "required": [ + "active_sandbox_count", + "idle_retained_filesystem_count", + "retained_filesystem_age_ms", + "estimated_retained_filesystem_gb_hours", + "stuck_sandbox_count_by_state", + "average_cold_start_latency_ms", + "average_resume_latency_ms" + ] + }, + "AgentSession": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "state": { + "type": "string", + "enum": [ + "ACTIVE", + "WAITING_FOR_INPUT", + "WAITING_FOR_PERMISSION", + "COMPLETED", + "FAILED", + "CANCELLED", + "ARCHIVED" + ] + }, + "origin": { + "type": "string", + "enum": [ + "DASHBOARD", + "API", + "MCP", + "ACP", + "AMBIENT", + "SYSTEM" + ] + }, + "title": { + "type": "string", + "nullable": true + }, + "communication_profile": { + "type": "string", + "enum": [ + "BEGINNER", + "INTERMEDIATE", + "ADVANCED", + "EXPERT", + "ADAPTIVE" + ] + }, + "created_by": { + "type": "string" + }, + "parent_session_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "forked_from_session_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "spawned_by_turn_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "agent_role": { + "type": "string", + "nullable": true + }, + "current_sandbox_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "last_event_cursor": { + "type": "string", + "nullable": true + }, + "events_retained_until": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "filesystem_retained_until": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "filesystem_pinned": { + "type": "boolean" + }, + "usage_summary": { + "$ref": "#/components/schemas/AgentUsageSummary" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "organization_id", + "agent_id", + "state", + "origin", + "title", + "communication_profile", + "created_by", + "parent_session_id", + "forked_from_session_id", + "spawned_by_turn_id", + "agent_role", + "current_sandbox_id", + "last_event_cursor", + "events_retained_until", + "filesystem_retained_until", + "filesystem_pinned", + "usage_summary", + "created_at", + "updated_at", + "etag" + ] + }, + "AgentSessionList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentSession" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AgentWorkConflictList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentWorkConflict" + } + } + }, + "required": [ + "data" + ], + "additionalProperties": false + }, + "AgentWorkConflict": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "event_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "event_type": { + "type": "string", + "enum": [ + "message.created", + "widget.created", + "artifact.created", + "progress.updated", + "execution_environment.started", + "execution_environment.stopped", + "execution_environment.resumed", + "execution_environment.deleted", + "execution_environment.failed", + "handoff_summary.created", + "turn.cancelled" + ] + }, + "reason": { + "type": "string", + "minLength": 1, + "maxLength": 500 + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "agent_id", + "session_id", + "turn_id", + "event_id", + "event_type", + "reason", + "created_at" + ], + "additionalProperties": false + }, + "SetAgentSessionRetentionBody": { + "type": "object", + "properties": { + "events_retained_until": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "filesystem_retained_until": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "filesystem_pinned": { + "type": "boolean" + }, + "retention_reason": { + "type": "string", + "enum": [ + "SESSION_ACTIVE", + "PINNED", + "POLICY", + "TERMINAL_GRACE", + "MANUAL_DELETE" + ] + } + }, + "required": [ + "events_retained_until", + "filesystem_retained_until", + "filesystem_pinned", + "retention_reason" + ], + "additionalProperties": false + }, + "AgentTurn": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "state": { + "type": "string", + "enum": [ + "QUEUED", + "RUNNING", + "WAITING_FOR_INPUT", + "WAITING_FOR_PERMISSION", + "COMPLETED", + "FAILED", + "CANCELLED" + ] + }, + "origin": { + "type": "string", + "enum": [ + "DASHBOARD", + "API", + "MCP", + "ACP", + "AMBIENT", + "SYSTEM" + ] + }, + "input": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "message" + ] + }, + "content": { + "type": "string" + } + }, + "required": [ + "type", + "content" + ] + }, + "runtime_hint": { + "type": "string", + "enum": [ + "AUTO", + "CODE_MODE", + "RETAINED_RUNTIME" + ] + }, + "model": { + "type": "string", + "nullable": true + }, + "created_by": { + "type": "string" + }, + "started_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "completed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "runtime_decision": { + "type": "string", + "nullable": true, + "enum": [ + "ALLOWED", + "DENIED", + "APPROVAL_REQUIRED", + null + ] + }, + "decision_reason": { + "type": "string", + "nullable": true + }, + "resolved_execution_mode": { + "type": "string", + "nullable": true, + "enum": [ + "CODE_MODE", + "RETAINED_RUNTIME", + null + ] + }, + "admission_error": { + "type": "object", + "nullable": true, + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "message" + ] + }, + "usage_summary": { + "$ref": "#/components/schemas/AgentUsageSummary" + }, + "failure": { + "type": "object", + "nullable": true, + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "message" + ] + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "organization_id", + "agent_id", + "session_id", + "state", + "origin", + "input", + "runtime_hint", + "model", + "created_by", + "started_at", + "completed_at", + "runtime_decision", + "decision_reason", + "resolved_execution_mode", + "admission_error", + "usage_summary", + "failure", + "created_at", + "updated_at", + "etag" + ] + }, + "AgentTurnList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentTurn" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AgentEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "sequence": { + "type": "integer" + }, + "cursor": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "message.created", + "widget.created", + "artifact.created", + "progress.updated", + "execution_environment.started", + "execution_environment.stopped", + "execution_environment.resumed", + "execution_environment.deleted", + "execution_environment.failed", + "handoff_summary.created", + "turn.cancelled" + ] + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "data": { + "nullable": true + } + }, + "required": [ + "id", + "workspace_id", + "agent_id", + "session_id", + "turn_id", + "sequence", + "cursor", + "type", + "created_at" + ] + }, + "AgentProviderExchangeList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentProviderExchange" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "AgentProviderExchange": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "provider": { + "type": "string" + }, + "model": { + "type": "string", + "nullable": true + }, + "fallback_from_model": { + "type": "string", + "nullable": true + }, + "fallback_reason": { + "type": "string", + "nullable": true + }, + "credential_mode": { + "type": "string", + "enum": [ + "PLATFORM_SUBSCRIPTION", + "PLATFORM_API", + "WORKSPACE_BYOK" + ] + }, + "credential_secret_id": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 54 + }, + "requested_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "responded_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "provider_cost_cents": { + "type": "integer", + "minimum": 0 + }, + "provider_token_count": { + "type": "integer", + "minimum": 0 + }, + "token_counts": { + "type": "object", + "nullable": true, + "properties": { + "input": { + "type": "integer", + "minimum": 0 + }, + "output": { + "type": "integer", + "minimum": 0 + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "message_summary": { + "type": "string", + "nullable": true + }, + "upstream_error_code": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + } + }, + "required": [ + "id", + "workspace_id", + "organization_id", + "agent_id", + "session_id", + "turn_id", + "provider", + "model", + "fallback_from_model", + "fallback_reason", + "credential_mode", + "credential_secret_id", + "requested_at", + "responded_at", + "provider_cost_cents", + "provider_token_count", + "token_counts", + "message_summary", + "upstream_error_code", + "created_at" + ] + }, + "AgentEventList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentEvent" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "ApprovalRequestList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApprovalRequest" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "ApprovalRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "state": { + "type": "string", + "enum": [ + "PENDING", + "APPROVED", + "REJECTED" + ] + }, + "title": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "actions": { + "type": "array", + "items": { + "nullable": true + }, + "default": [] + }, + "created_by": { + "type": "string" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "agent_id", + "session_id", + "turn_id", + "state", + "title", + "summary", + "created_by", + "created_at", + "updated_at", + "etag" + ] + }, + "WorkspaceSubdomain": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63 + }, + "fqdn": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "status": { + "type": "string", + "enum": [ + "active", + "propagating", + "reserved" + ], + "description": "Current workspace subdomain lifecycle state." + }, + "name_changed_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "name", + "fqdn", + "status", + "name_changed_at", + "created_at", + "updated_at", + "etag" + ] + }, + "SetWorkspaceSubdomainNameBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63 + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "PreviewHostnameList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PreviewHostname" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "PreviewHostname": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + }, + "binding": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "pinned" + ] + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "render_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "floating" + ] + }, + "track": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "track", + "render_id" + ], + "additionalProperties": false + } + ] + }, + "status": { + "type": "string", + "enum": [ + "provisioning", + "active", + "evicted", + "releasing" + ], + "description": "Current preview hostname lifecycle state." + }, + "last_seen_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "install_id", + "hostname", + "protocol", + "routing_mode", + "binding", + "status", + "last_seen_at", + "created_at", + "updated_at", + "etag" + ] + }, + "BindPinnedPreviewHostnameBody": { + "type": "object", + "properties": { + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "default": "http", + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "default": "through_dispatcher", + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + } + }, + "required": [ + "render_id" + ], + "additionalProperties": false + }, + "BindFloatingPreviewHostnameBody": { + "type": "object", + "properties": { + "track": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "render_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "default": "http", + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "default": "through_dispatcher", + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + } + }, + "required": [ + "track", + "render_id" + ], + "additionalProperties": false + }, + "CustomDomainList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomDomain" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "CustomDomain": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "target": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "install_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "cluster" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "cluster_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "external" + ] + }, + "endpoint": { + "type": "string", + "format": "uri" + }, + "mtls_secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "endpoint" + ], + "additionalProperties": false + } + ] + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + }, + "ssl": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "pending_validation", + "active", + "failed" + ] + }, + "validation_records": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "required": [ + "status" + ] + }, + "status": { + "type": "string", + "enum": [ + "provisioning", + "active", + "failed", + "releasing" + ] + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "updated_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "etag": { + "type": "string" + } + }, + "required": [ + "id", + "workspace_id", + "hostname", + "target", + "protocol", + "routing_mode", + "ssl", + "status", + "created_at", + "updated_at", + "etag" + ] + }, + "CreateCustomDomainBody": { + "type": "object", + "properties": { + "hostname": { + "type": "string", + "minLength": 1, + "maxLength": 253 + }, + "target": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "install_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "cluster" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "cluster_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "external" + ] + }, + "endpoint": { + "type": "string", + "format": "uri" + }, + "mtls_secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "endpoint" + ], + "additionalProperties": false + } + ] + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "default": "http", + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "default": "through_dispatcher", + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + } + }, + "required": [ + "hostname", + "target" + ], + "additionalProperties": false + }, + "UpdateCustomDomainBody": { + "type": "object", + "properties": { + "target": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "install" + ] + }, + "install_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "kind", + "install_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "cluster" + ] + }, + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "cluster_id" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "external" + ] + }, + "endpoint": { + "type": "string", + "format": "uri" + }, + "mtls_secret_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "kind", + "endpoint" + ], + "additionalProperties": false + } + ] + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "websocket", + "grpc" + ], + "description": "Transport class for route forwarding." + }, + "routing_mode": { + "type": "string", + "enum": [ + "through_dispatcher", + "bypass_dispatcher" + ], + "description": "Whether traffic uses the dispatcher Worker or bypasses it." + } + }, + "additionalProperties": false + }, + "CloudflareCredentialList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CloudflareCredential" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ] + }, + "CloudflareCredential": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "name": { + "type": "string", + "example": "Production Cloudflare" + }, + "account_id": { + "type": "string", + "description": "Cloudflare account ID." + }, + "origin_zone_id": { + "type": "string", + "nullable": true, + "description": "Cloudflare zone ID used for Access-protected origin hostnames." + }, + "origin_hostname_suffix": { + "type": "string", + "nullable": true, + "description": "Hostname suffix used for Access-protected origin hostnames." + }, + "is_active": { + "type": "boolean", + "description": "Whether the credential is active" + }, + "created_at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp (seconds)" + }, + "last_used_at": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "Unix timestamp (seconds), null if never used" + } + }, + "required": [ + "id", + "name", + "account_id", + "origin_zone_id", + "origin_hostname_suffix", + "is_active", + "created_at", + "last_used_at" + ] + }, + "CreateCloudflareCredentialBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "example": "Production Cloudflare" + }, + "account_id": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$", + "description": "Cloudflare account ID." + }, + "origin_zone_id": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$", + "description": "Cloudflare zone ID used for Access-protected origin hostnames." + }, + "origin_hostname_suffix": { + "type": "string", + "minLength": 1, + "maxLength": 253, + "description": "Hostname suffix used for Access-protected origin hostnames." + }, + "api_token": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "Cloudflare API token. Stored as a platform Secret; never returned." + } + }, + "required": [ + "name", + "account_id", + "origin_zone_id", + "origin_hostname_suffix", + "api_token" + ], + "additionalProperties": false + }, + "AccessDecision": { + "type": "object", + "properties": { + "decision": { + "$ref": "#/components/schemas/AccessDecisionResult" + }, + "action": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "id", + "name" + ], + "additionalProperties": false + }, + "reasons": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AccessReason" + } + } + }, + "required": [ + "decision", + "action", + "reasons" + ], + "additionalProperties": false + }, + "AccessDecisionResult": { + "oneOf": [ + { + "type": "object", + "properties": { + "result": { + "type": "string", + "enum": [ + "allowed" + ] + } + }, + "required": [ + "result" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "result": { + "type": "string", + "enum": [ + "denied" + ] + }, + "message": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "result", + "message" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "result": { + "type": "string", + "enum": [ + "unknown" + ] + }, + "message": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "result", + "message" + ], + "additionalProperties": false + } + ] + }, + "AccessReason": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "catalog_default", + "external_feature_flag", + "external_billing_entitlement", + "workspace_access_status", + "admin_override", + "policy_rule", + "quota_limit", + "quota_usage", + "quota_override", + "actor_context", + "resource_state", + "workspace_membership", + "workspace_role", + "organization_membership", + "organization_role", + "workspace_class", + "resource_ownership", + "relationship", + "domain_policy" + ] + }, + "result": { + "type": "string", + "enum": [ + "allowed", + "denied", + "not_evaluated" + ] + }, + "key": { + "type": "string" + }, + "source": { + "type": "string" + }, + "message": { + "type": "string" + }, + "metric": { + "type": "string" + }, + "scope": { + "type": "string", + "enum": [ + "global", + "organization", + "workspace", + "user" + ] + }, + "limit": { + "type": "number" + }, + "usage": { + "type": "number" + }, + "remaining": { + "type": "number" + }, + "resourceId": { + "type": "string" + }, + "resourceType": { + "type": "string" + }, + "relationship": { + "type": "string" + } + }, + "required": [ + "kind", + "result" + ], + "additionalProperties": false + }, + "ExplainAccessDecisionBody": { + "oneOf": [ + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offers.create_via_channel" + ] + }, + "resource": { + "$ref": "#/components/schemas/OfferChannelCreateResource" + }, + "context": { + "$ref": "#/components/schemas/OfferChannelDecisionContext" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offers.create_non_channel_paid_product_offer" + ] + }, + "resource": { + "$ref": "#/components/schemas/NonChannelPaidProductOfferResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offers.create_non_billable_test_offer" + ] + }, + "resource": { + "$ref": "#/components/schemas/NonBillableTestOfferResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offer_channels.create" + ] + }, + "resource": { + "$ref": "#/components/schemas/OfferChannelCreateDecisionResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offer_channels.inspect" + ] + }, + "resource": { + "$ref": "#/components/schemas/OfferChannelInspectResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "channel_policies.approve" + ] + }, + "resource": { + "$ref": "#/components/schemas/ChannelPolicyApproveResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "channel_policies.activate" + ] + }, + "resource": { + "$ref": "#/components/schemas/ChannelPolicyActivateResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offers.approve_channel_offer" + ] + }, + "resource": { + "$ref": "#/components/schemas/OfferChannelModerationResource" + }, + "context": { + "$ref": "#/components/schemas/OfferChannelDecisionContext" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "offers.reject_channel_offer" + ] + }, + "resource": { + "$ref": "#/components/schemas/OfferChannelModerationResource" + }, + "context": { + "$ref": "#/components/schemas/OfferChannelDecisionContext" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "workspaces.inspect_class" + ] + }, + "resource": { + "$ref": "#/components/schemas/WorkspaceClassResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "workspaces.inspect_membership" + ] + }, + "resource": { + "$ref": "#/components/schemas/WorkspaceMembershipResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.create" + ] + }, + "resource": { + "$ref": "#/components/schemas/ProductCockpitResource" + } + }, + "required": [ + "permission" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.get" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.update" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.archive" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.unarchive" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.inspect_readiness" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.inspect_offer_creation" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.inspect_channels" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "products.inspect_installs" + ] + }, + "resource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "product_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "packages.create" + ] + }, + "resource": { + "$ref": "#/components/schemas/PackageCockpitResource" + } + }, + "required": [ + "permission" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "packages.import_published_package" + ] + }, + "resource": { + "$ref": "#/components/schemas/PackageCockpitResource" + } + }, + "required": [ + "permission" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "packages.get" + ] + }, + "resource": { + "type": "object", + "properties": { + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "package_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "package_versions.get" + ] + }, + "resource": { + "type": "object", + "properties": { + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "package_id", + "package_version_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "package_versions.inputs" + ] + }, + "resource": { + "type": "object", + "properties": { + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "package_id", + "package_version_id", + "workspace_id" + ], + "additionalProperties": false + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "subject": { + "$ref": "#/components/schemas/AccessSubject" + }, + "permission": { + "type": "string", + "enum": [ + "catalog_actions.explain" + ] + }, + "resource": { + "$ref": "#/components/schemas/CatalogActionExplainResource" + } + }, + "required": [ + "permission", + "resource" + ], + "additionalProperties": false, + "x-platform-visibility": "ADMIN" + } + ] + }, + "AccessSubject": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "minLength": 1 + }, + "organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "additionalProperties": false + }, + "OfferChannelCreateResource": { + "type": "object", + "properties": { + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "commercial_mode": { + "type": "string", + "enum": [ + "paid", + "non_billable_test" + ] + } + }, + "required": [ + "offer_channel_id", + "product_id", + "commercial_mode" + ], + "additionalProperties": false + }, + "OfferChannelDecisionContext": { + "type": "object", + "properties": { + "selected_organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "stripe_mode": { + "type": "string", + "enum": [ + "live", + "test", + "sandbox" + ] + } + }, + "additionalProperties": false + }, + "NonChannelPaidProductOfferResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "commercial_mode": { + "type": "string", + "enum": [ + "paid" + ] + } + }, + "required": [ + "workspace_id", + "product_id", + "package_version_id", + "commercial_mode" + ], + "additionalProperties": false + }, + "NonBillableTestOfferResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "target_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "target_workspace_class": { + "type": "string", + "enum": [ + "standard", + "platform", + "sandbox" + ] + }, + "commercial_mode": { + "type": "string", + "enum": [ + "non_billable_test" + ] + } + }, + "required": [ + "workspace_id", + "product_id", + "package_version_id", + "commercial_mode" + ], + "additionalProperties": false + }, + "OfferChannelCreateDecisionResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "partner_organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "workspace_id" + ], + "additionalProperties": false + }, + "OfferChannelInspectResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + } + }, + "required": [ + "workspace_id" + ], + "additionalProperties": false + }, + "ChannelPolicyApproveResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "channel_policy_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft" + ] + } + }, + "required": [ + "workspace_id", + "offer_channel_id", + "channel_policy_id", + "resource_state" + ], + "additionalProperties": false + }, + "ChannelPolicyActivateResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "channel_policy_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "resource_state": { + "type": "string", + "enum": [ + "approved" + ] + } + }, + "required": [ + "workspace_id", + "offer_channel_id", + "channel_policy_id", + "resource_state" + ], + "additionalProperties": false + }, + "OfferChannelModerationResource": { + "type": "object", + "properties": { + "offer_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "owner_workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "resource_state": { + "type": "string", + "enum": [ + "pending_approval", + "approved", + "rejected" + ] + }, + "platform_policy_snapshot_id": { + "type": "string", + "minLength": 1, + "x-platform-visibility": "ADMIN" + }, + "partner_price_band_key": { + "type": "string", + "minLength": 1, + "x-platform-visibility": "TRUSTED_PARTNER" + } + }, + "required": [ + "offer_id", + "offer_channel_id", + "owner_workspace_id", + "resource_state" + ], + "additionalProperties": false + }, + "WorkspaceClassResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "required_class": { + "type": "string", + "enum": [ + "standard", + "platform", + "sandbox" + ] + } + }, + "required": [ + "workspace_id" + ], + "additionalProperties": false + }, + "WorkspaceMembershipResource": { + "type": "object", + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "required_roles": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "owner", + "admin", + "member" + ] + } + } + }, + "required": [ + "workspace_id" + ], + "additionalProperties": false + }, + "ProductCockpitResource": { + "type": "object", + "properties": { + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "resource_state": { + "type": "string", + "enum": [ + "draft", + "active", + "archived" + ] + } + }, + "required": [ + "workspace_id" + ], + "additionalProperties": false + }, + "PackageCockpitResource": { + "type": "object", + "properties": { + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + } + }, + "required": [ + "workspace_id" + ], + "additionalProperties": false + }, + "CatalogActionExplainResource": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "minLength": 1 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "user_id": { + "type": "string", + "minLength": 1 + }, + "product_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "package_version_id": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "offer_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "offer_channel_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "channel_policy_id": { + "type": "string", + "minLength": 1, + "maxLength": 56 + } + }, + "required": [ + "action_id" + ], + "additionalProperties": false, + "x-platform-visibility": "ADMIN" + }, + "AdminCapabilityList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminCapability" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminCapability": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "networking" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "surfaces": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "web", + "api", + "worker", + "docs" + ] + } + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminCapabilityAction" + } + }, + "flags": { + "type": "array", + "items": { + "type": "string" + } + }, + "entitlements": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "name", + "owner", + "surfaces", + "actions", + "flags", + "entitlements" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminCapabilityAction": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "custom_domains.use_dispatcher_bypass" + }, + "name": { + "type": "string" + }, + "access": { + "$ref": "#/components/schemas/AdminCapabilityActionAccess" + }, + "quota_metrics": { + "type": "array", + "items": { + "type": "string" + } + }, + "operations": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "name", + "access" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminCapabilityActionAccess": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "baseline" + ] + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "feature_flagged" + ] + }, + "flags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "flags" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "entitled" + ] + }, + "entitlements": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "entitlements" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "admin" + ] + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "internal" + ] + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + } + ], + "x-platform-visibility": "ADMIN" + }, + "AdminDirectoryOrganizationList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminDirectoryOrganization" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminDirectoryOrganization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "number" + }, + "member_count": { + "type": "integer", + "minimum": 0 + }, + "workspace_count": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "id", + "name", + "slug", + "created_at", + "member_count", + "workspace_count" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminDirectoryUserList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminDirectoryUser" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminDirectoryUser": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "email_verified": { + "type": "boolean" + }, + "workspace_count": { + "type": "integer", + "minimum": 0 + }, + "organization_count": { + "type": "integer", + "minimum": 0 + }, + "created_at": { + "type": "number" + } + }, + "required": [ + "id", + "name", + "email", + "email_verified", + "workspace_count", + "organization_count", + "created_at" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminDirectoryWorkspaceList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminDirectoryWorkspace" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminDirectoryWorkspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "organization_name": { + "type": "string" + }, + "workspace_class": { + "type": "string", + "enum": [ + "standard", + "platform", + "sandbox" + ] + }, + "plan_tier": { + "type": "string" + }, + "access_status": { + "type": "string", + "enum": [ + "active", + "payment_grace", + "restricted", + "suspended", + "ended", + "reactivating" + ] + }, + "accessible": { + "type": "boolean" + }, + "member_count": { + "type": "integer", + "minimum": 0 + }, + "cluster_count": { + "type": "integer", + "minimum": 0 + }, + "product_count": { + "type": "integer", + "minimum": 0 + }, + "operation_count": { + "type": "integer", + "minimum": 0 + }, + "created_at": { + "type": "number" + } + }, + "required": [ + "id", + "name", + "slug", + "workspace_class", + "plan_tier", + "member_count", + "cluster_count", + "product_count", + "operation_count", + "created_at" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminAccessOverrideList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminAccessOverride" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminAccessOverride": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "target_type": { + "type": "string", + "enum": [ + "feature_flag", + "entitlement" + ] + }, + "key": { + "type": "string" + }, + "scope": { + "type": "string", + "enum": [ + "global", + "organization", + "workspace" + ] + }, + "organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "effect": { + "type": "string", + "enum": [ + "allow", + "deny" + ] + }, + "previous_effect": { + "type": "string", + "nullable": true, + "enum": [ + "allow", + "deny", + null + ] + }, + "new_effect": { + "type": "string", + "nullable": true, + "enum": [ + "allow", + "deny", + null + ] + }, + "reason": { + "type": "string" + }, + "created_by": { + "type": "string", + "minLength": 1 + }, + "created_at": { + "type": "number" + }, + "updated_by": { + "type": "string", + "minLength": 1 + }, + "updated_at": { + "type": "number" + }, + "expires_at": { + "type": "number" + }, + "revoked_at": { + "type": "number" + } + }, + "required": [ + "id", + "target_type", + "key", + "scope", + "effect", + "previous_effect", + "new_effect", + "reason", + "created_by", + "created_at", + "updated_by", + "updated_at" + ], + "x-platform-visibility": "ADMIN" + }, + "CreateAdminAccessOverrideBody": { + "type": "object", + "properties": { + "target_type": { + "type": "string", + "enum": [ + "feature_flag", + "entitlement" + ] + }, + "key": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "scope": { + "type": "string", + "enum": [ + "global", + "organization", + "workspace" + ] + }, + "organization_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "effect": { + "type": "string", + "enum": [ + "allow", + "deny" + ] + }, + "reason": { + "type": "string", + "minLength": 1, + "maxLength": 500 + }, + "expires_at": { + "type": "number" + } + }, + "required": [ + "target_type", + "key", + "scope", + "effect", + "reason" + ], + "additionalProperties": false, + "x-platform-visibility": "ADMIN" + }, + "AdminQuotaOverrideList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminQuotaOverride" + } + }, + "has_more": { + "type": "boolean", + "description": "True if more items exist after this page." + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Opaque cursor for the next page, or null if no more pages." + } + }, + "required": [ + "data", + "has_more", + "next_cursor" + ], + "x-platform-visibility": "ADMIN" + }, + "AdminQuotaOverride": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "scope": { + "type": "string", + "enum": [ + "user", + "workspace" + ] + }, + "user_id": { + "type": "string", + "minLength": 1 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "metric": { + "type": "string" + }, + "limit": { + "type": "number" + }, + "previous_limit": { + "type": "number", + "nullable": true + }, + "new_limit": { + "type": "number", + "nullable": true + }, + "reason": { + "type": "string" + }, + "created_by": { + "type": "string", + "minLength": 1 + }, + "created_at": { + "type": "number" + }, + "updated_by": { + "type": "string", + "minLength": 1 + }, + "updated_at": { + "type": "number" + }, + "revoked_at": { + "type": "number" + } + }, + "required": [ + "id", + "scope", + "metric", + "limit", + "previous_limit", + "new_limit" + ], + "x-platform-visibility": "ADMIN" + }, + "SetAdminQuotaOverrideBody": { + "type": "object", + "properties": { + "scope": { + "type": "string", + "enum": [ + "user", + "workspace" + ] + }, + "user_id": { + "type": "string", + "minLength": 1 + }, + "workspace_id": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "metric": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "limit": { + "type": "integer", + "minimum": 0 + }, + "reason": { + "type": "string", + "minLength": 1, + "maxLength": 500 + } + }, + "required": [ + "scope", + "metric", + "limit", + "reason" + ], + "additionalProperties": false, + "x-platform-visibility": "ADMIN" + } + }, + "parameters": {} + }, + "paths": { + "/v1/compute/machines": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.createMachine", + "tags": [ + "Compute" + ], + "summary": "Create a machine", + "description": "Provisions a new machine in the specified cluster with the given compute configuration.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "config_ref": { + "type": "string", + "description": "ComputeConfig ID" + }, + "cluster_id": { + "type": "string", + "description": "Cluster ID" + }, + "node_claim": { + "nullable": true, + "description": "Machine requirements (instance type, resources, taints)" + } + }, + "required": [ + "config_ref", + "cluster_id" + ] + } + } + } + }, + "responses": { + "201": { + "description": "Machine created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeMachine" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Config not found (NodeClassNotReady)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + }, + "503": { + "description": "No capacity available (InsufficientCapacity)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.listMachines", + "tags": [ + "Compute" + ], + "summary": "List machines in cluster", + "description": "Lists all machines for a cluster.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cluster ID" + }, + "required": true, + "description": "Cluster ID", + "name": "cluster", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of machines", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ComputeMachine" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/compute/machines/{providerId}": { + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.deleteMachine", + "tags": [ + "Compute" + ], + "summary": "Delete a machine", + "description": "Deletes a machine by provider ID. The node is drained before the cloud server is terminated.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Provider-assigned machine ID" + }, + "required": true, + "description": "Provider-assigned machine ID", + "name": "providerId", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Machine deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Machine not found (NodeClaimNotFound)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.getMachine", + "tags": [ + "Compute" + ], + "summary": "Get machine status", + "description": "Returns current state of a machine including conditions and provider metadata.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Provider-assigned machine ID" + }, + "required": true, + "description": "Provider-assigned machine ID", + "name": "providerId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Machine details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeMachine" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Machine not found (NodeClaimNotFound)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + } + }, + "/v1/compute/instance_types": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.listInstanceTypes", + "tags": [ + "Compute" + ], + "summary": "List available instance types", + "description": "Returns instance types with pricing for a compute config. Returns available instance types for provisioning. Results are cached.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Config name (optional — derived from cluster context when omitted)" + }, + "required": false, + "description": "Config name (optional — derived from cluster context when omitted)", + "name": "config", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Available instance types", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstanceType" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Config not found (NodeClassNotReady)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + } + }, + "/v1/compute/machines/{providerId}/drift": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.checkMachineDrift", + "tags": [ + "Compute" + ], + "summary": "Check if machine has drifted", + "description": "Checks if a machine has drifted from its desired compute configuration.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Provider-assigned machine ID" + }, + "required": true, + "description": "Provider-assigned machine ID", + "name": "providerId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Drift result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DriftResult" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/compute/machines/{providerId}/suspend": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.suspendMachine", + "tags": [ + "Compute" + ], + "summary": "Suspend a machine", + "description": "Snapshots the machine disk, deletes the cloud server to stop billing, and creates a suspension record.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Provider-assigned machine ID" + }, + "required": true, + "description": "Provider-assigned machine ID", + "name": "providerId", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Suspend workflow started" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Machine not found (NodeClaimNotFound)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + } + }, + "/v1/compute/suspensions/{id}/resume": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.resumeSuspension", + "tags": [ + "Compute" + ], + "summary": "Resume a suspended machine", + "description": "Restores the machine from its snapshot, creates a new cloud server.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Suspension ID" + }, + "required": true, + "description": "Suspension ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Resume workflow started" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Suspension not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + } + }, + "/v1/compute/suspensions": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.listSuspensions", + "tags": [ + "Compute" + ], + "summary": "List suspended machines", + "description": "Lists all suspended machines for the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "List of suspensions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Suspension" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/compute/suspensions/{id}": { + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.deleteSuspension", + "tags": [ + "Compute" + ], + "summary": "Delete a suspension", + "description": "Deletes the snapshot and suspension record permanently.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Suspension ID" + }, + "required": true, + "description": "Suspension ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Suspension deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Suspension not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + } + }, + "/v1/compute/configs": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.listConfigs", + "tags": [ + "Compute" + ], + "summary": "List compute configs", + "description": "Lists compute configs for the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of compute configs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfigList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.createConfig", + "tags": [ + "Compute" + ], + "summary": "Create a compute config", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "provider": { + "type": "string", + "enum": [ + "hcloud" + ] + }, + "region": { + "type": "string", + "minLength": 1 + }, + "image": { + "type": "string", + "minLength": 1 + }, + "machine_type_filter": { + "type": "string", + "description": "Glob pattern to filter available instance types (e.g., \"cx*\" for shared CPU, \"cpx*\" for dedicated)" + }, + "secret_id": { + "type": "string", + "description": "Secret ID for BYOM (bring your own machine). Omit to use platform-managed defaults." + } + }, + "required": [ + "name", + "provider", + "region", + "image" + ] + } + } + } + }, + "responses": { + "201": { + "description": "Config created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatedComputeConfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/compute/configs/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.getConfig", + "tags": [ + "Compute" + ], + "summary": "Get a compute config", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "ComputeConfig ID" + }, + "required": true, + "description": "ComputeConfig ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Compute config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Config not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.deleteConfig", + "tags": [ + "Compute" + ], + "summary": "Delete a compute config", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "ComputeConfig ID" + }, + "required": true, + "description": "ComputeConfig ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Config deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Config not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + }, + "409": { + "description": "Config has active machines", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeError" + } + } + } + } + } + } + }, + "/v1/clusters/{clusterId}/compute_status": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.getClusterStatus", + "tags": [ + "Compute" + ], + "summary": "Get cluster compute status", + "description": "Returns auto-scaling state, machine count, and limits for a cluster.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cluster ID" + }, + "required": true, + "description": "Cluster ID", + "name": "clusterId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Compute status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "auto_scaling": { + "type": "string", + "enum": [ + "active", + "paused" + ] + }, + "machines": { + "type": "number" + }, + "max_machines": { + "type": "number" + } + }, + "required": [ + "auto_scaling", + "machines", + "max_machines" + ] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{clusterId}/compute_settings": { + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "compute.updateClusterSettings", + "tags": [ + "Compute" + ], + "summary": "Update cluster compute settings", + "description": "Controls auto-scaling behavior and machine limits for a cluster.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cluster ID" + }, + "required": true, + "description": "Cluster ID", + "name": "clusterId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "auto_scaling_enabled": { + "type": "boolean" + }, + "max_machines": { + "type": "number", + "minimum": 0, + "maximum": 100 + } + } + } + } + } + }, + "responses": { + "204": { + "description": "Settings updated" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Akua-Context required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.listSnippetsForApi" + }, + "operationId": "snippets.list", + "tags": [ + "Snippets" + ], + "summary": "List snippets in workspace", + "description": "Returns all snippets belonging to the workspace specified in the workspace context.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of snippets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnippetList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "snippets.create", + "tags": [ + "Snippets" + ], + "summary": "Create snippet", + "description": "Creates a reusable code snippet in the workspace. Snippets are async JavaScript functions executed in a sandboxed runtime with access to platform.request() for API calls.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "example": "Cluster Resource Audit" + }, + "description": { + "type": "string", + "maxLength": 500, + "description": "Optional human-readable description" + }, + "code": { + "type": "string", + "minLength": 1, + "maxLength": 50000, + "description": "Async JavaScript function body. Executed in a sandboxed runtime with access to platform.request()." + }, + "display_type": { + "type": "string", + "enum": [ + "table", + "stat", + "json", + "logs" + ], + "description": "Controls how the snippet result is rendered in dashboard widgets" + }, + "visibility": { + "type": "string", + "enum": [ + "workspace", + "session" + ], + "description": "Whether the snippet is reusable workspace state or scoped to an agent session." + }, + "origin": { + "type": "string", + "enum": [ + "user", + "agent", + "system" + ], + "description": "Who authored the snippet descriptor." + }, + "agent_session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "agent_turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "purpose": { + "type": "string", + "enum": [ + "general", + "prepared_action", + "reactive_read", + "widget" + ] + } + }, + "required": [ + "name", + "code", + "display_type" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Snippet created", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "snippet_id": { + "type": "string" + } + }, + "required": [ + "snippet_id" + ] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets:usage": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.listSnippetUsageForApi" + }, + "operationId": "snippets.listUsage", + "tags": [ + "Snippets" + ], + "summary": "List snippet dashboard usage in workspace", + "description": "Returns dashboard references for snippets in the workspace specified in the workspace context.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Snippet dashboard usage", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnippetUsageList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets/{id}:usage": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.getSnippetUsageForApi" + }, + "operationId": "snippets.getUsage", + "tags": [ + "Snippets" + ], + "summary": "Get snippet dashboard usage", + "description": "Returns dashboard references for one snippet.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Snippet ID" + }, + "required": true, + "description": "Snippet ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Snippet dashboard usage", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnippetUsage" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.getSnippetForApi" + }, + "operationId": "snippets.get", + "tags": [ + "Snippets" + ], + "summary": "Get snippet details", + "description": "Returns a snippet including its code and display type.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Snippet ID" + }, + "required": true, + "description": "Snippet ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Snippet details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Snippet" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "snippets.update", + "tags": [ + "Snippets" + ], + "summary": "Update snippet", + "description": "Updates snippet properties. Only provided fields are changed. Dashboards using this snippet will pick up code changes on next run.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Snippet ID" + }, + "required": true, + "description": "Snippet ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "code": { + "type": "string", + "minLength": 1, + "maxLength": 50000 + }, + "display_type": { + "type": "string", + "enum": [ + "table", + "stat", + "json", + "logs" + ], + "description": "Controls how the snippet result is rendered in dashboard widgets" + }, + "visibility": { + "type": "string", + "enum": [ + "workspace", + "session" + ], + "description": "Whether the snippet is reusable workspace state or scoped to an agent session." + }, + "purpose": { + "type": "string", + "enum": [ + "general", + "prepared_action", + "reactive_read", + "widget" + ] + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Snippet updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "snippet_id": { + "type": "string" + } + }, + "required": [ + "snippet_id" + ] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "snippets.delete", + "tags": [ + "Snippets" + ], + "summary": "Delete snippet", + "description": "Permanently deletes a snippet. Fails with 409 if the snippet is referenced by any dashboard widgets.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Snippet ID" + }, + "required": true, + "description": "Snippet ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Snippet deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets:execute": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "snippets.execute", + "tags": [ + "Snippets" + ], + "summary": "Execute ad-hoc snippet code", + "description": "Executes ad-hoc JavaScript in the snippet sandbox and returns the synchronous result. Does not persist a snippet or run resource.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteSnippetBody" + } + } + } + }, + "responses": { + "200": { + "description": "Snippet execution result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteSnippetResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets/{id}:execute": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "snippets.executeStored", + "tags": [ + "Snippets" + ], + "summary": "Execute stored snippet", + "description": "Fetches a stored snippet by ID server-side, executes its code in the snippet sandbox, and returns the synchronous result.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Snippet execution result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteSnippetResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets/{id}/runs": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "snippets.createRun", + "tags": [ + "Snippets" + ], + "summary": "Create snippet run", + "description": "Creates a new snippet run resource under a snippet and starts execution. Idempotent with Idempotency-Key; callers receive the created run resource and Location header.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSnippetRunBody" + } + } + } + }, + "responses": { + "201": { + "description": "Snippet run created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnippetRun" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.listSnippetRunsForApi" + }, + "operationId": "snippets.listRuns", + "tags": [ + "Snippets" + ], + "summary": "List snippet runs", + "description": "Returns runs for a snippet. Use `view=basic` for a compact listing.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "succeeded", + "failed", + "timed_out" + ] + }, + "required": false, + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic", + "description": "Control whether output and error details are included." + }, + "required": false, + "description": "Control whether output and error details are included.", + "name": "view", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of snippet runs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnippetRunList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/snippets/{id}/runs/{run_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.getSnippetRun" + }, + "operationId": "snippets.getRun", + "tags": [ + "Snippets" + ], + "summary": "Get snippet run", + "description": "Returns a single snippet run by ID.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "run_id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Snippet run details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnippetRun" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/dashboards": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.listDashboardsForApi" + }, + "operationId": "dashboards.list", + "tags": [ + "Dashboards" + ], + "summary": "List dashboards in workspace", + "description": "Returns all dashboards belonging to the workspace specified in the workspace context.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of dashboards", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.create", + "tags": [ + "Dashboards" + ], + "summary": "Create dashboard", + "description": "Creates a dashboard in the workspace. Widgets are added through the dashboard widgets sub-collection.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "example": "Cluster Overview" + }, + "description": { + "type": "string", + "maxLength": 500 + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Dashboard created", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "dashboard_id": { + "type": "string" + } + }, + "required": [ + "dashboard_id" + ] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/dashboards/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "snippet.ui.getDashboardForApi" + }, + "operationId": "dashboards.get", + "tags": [ + "Dashboards" + ], + "summary": "Get dashboard details", + "description": "Returns a dashboard including its widget layout and snippet references.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Dashboard ID" + }, + "required": true, + "description": "Dashboard ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Dashboard details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Dashboard" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.update", + "tags": [ + "Dashboards" + ], + "summary": "Update dashboard", + "description": "Update dashboard metadata. Widget mutations use the `/widgets` sub-collection.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Dashboard ID" + }, + "required": true, + "description": "Dashboard ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 500 + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Dashboard updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "dashboard_id": { + "type": "string" + } + }, + "required": [ + "dashboard_id" + ] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.delete", + "tags": [ + "Dashboards" + ], + "summary": "Delete dashboard", + "description": "Permanently deletes a dashboard. Referenced snippets are not affected.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Dashboard ID" + }, + "required": true, + "description": "Dashboard ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Dashboard deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/dashboards/{id}/widgets": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.createWidget", + "tags": [ + "Dashboards" + ], + "summary": "Create dashboard widget", + "description": "Creates a widget as a child resource under a dashboard.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "snippet_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "col_span": { + "anyOf": [ + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + } + ] + }, + "display_type": { + "type": "string", + "nullable": true, + "enum": [ + "table", + "stat", + "json", + "logs", + null + ], + "description": "Controls how the snippet result is rendered in dashboard widgets" + }, + "position": { + "type": "integer" + } + }, + "required": [ + "snippet_id", + "col_span" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Dashboard widget created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Widget" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.listWidgets", + "tags": [ + "Dashboards" + ], + "summary": "List dashboard widgets", + "description": "Lists widgets for a dashboard.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of dashboard widgets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WidgetList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/dashboards/{id}/widgets/{wgt_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.getWidget", + "tags": [ + "Dashboards" + ], + "summary": "Get dashboard widget", + "description": "Returns a single dashboard widget.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "wgt_id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Dashboard widget details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Widget" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.updateWidget", + "tags": [ + "Dashboards" + ], + "summary": "Update dashboard widget", + "description": "Updates widget placement and display settings.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "wgt_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "col_span": { + "anyOf": [ + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + } + ] + }, + "position": { + "type": "integer" + }, + "display_type": { + "type": "string", + "nullable": true, + "enum": [ + "table", + "stat", + "json", + "logs", + null + ], + "description": "Controls how the snippet result is rendered in dashboard widgets" + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Dashboard widget updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Widget" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "dashboards.deleteWidget", + "tags": [ + "Dashboards" + ], + "summary": "Delete dashboard widget", + "description": "Deletes a dashboard widget. Snippet references are preserved.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "wgt_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Dashboard widget deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.create", + "summary": "Create machine", + "description": "Creates a machine and returns a long-running operation envelope.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cluster_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "instance_type": { + "type": "string", + "minLength": 1 + }, + "compute_config_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "name": { + "type": "string", + "maxLength": 120 + }, + "node_claim": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "cluster_id", + "instance_type", + "compute_config_id" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "202": { + "description": "Machine creation accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "compute.ui.listMachinesForApi" + }, + "tags": [ + "Machines" + ], + "operationId": "machines.list", + "summary": "List machines", + "description": "Lists all machines in the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "cluster_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "ACTIVE", + "PROVISIONING", + "SUSPENDING", + "SUSPENDED", + "RESUMING", + "DELETING" + ], + "description": "Machine lifecycle state." + }, + "required": false, + "description": "Machine lifecycle state.", + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic" + }, + "required": false, + "name": "view", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Machine list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MachineList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.get", + "summary": "Get machine", + "description": "Returns a machine by ID.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Machine details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Machine" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.update", + "summary": "Update machine", + "description": "Updates machine metadata.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "anyOf": [ + { + "type": "string", + "maxLength": 120 + }, + { + "nullable": true + } + ] + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Machine updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Machine" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.delete", + "summary": "Delete machine", + "description": "Deletes a machine and returns a long-running operation envelope.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Machine deletion accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}:suspend": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.suspend", + "summary": "Suspend machine", + "description": "Suspends a machine and returns a long-running operation envelope. On providers that recycle instances during suspension, the machine ID stays stable but the public IP usually changes on resume unless a floating IP is attached.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspendMachineBody" + } + } + } + }, + "responses": { + "202": { + "description": "Machine suspend accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}:resume": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.resume", + "summary": "Resume machine", + "description": "Resumes a suspended machine and returns a long-running operation envelope. The machine ID stays stable, but provider_resource.public_ip can change after resume on providers that recycle instances during suspension.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResumeMachineBody" + } + } + } + }, + "responses": { + "202": { + "description": "Machine resume accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}/drift_reports": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.createDriftReport", + "summary": "Create machine drift report", + "description": "Runs drift detection and stores a dedicated report row.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "trigger": { + "type": "string" + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Machine drift report created", + "headers": { + "Location": { + "schema": { + "type": "string" + }, + "description": "Location of the drift report." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DriftReport" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.listDriftReports", + "summary": "List machine drift reports", + "description": "Lists historical drift reports for a machine.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "in_sync", + "drifted" + ], + "description": "Machine drift comparison state." + }, + "required": false, + "description": "Machine drift comparison state.", + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Drift report list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DriftReportList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}/drift_reports/{report_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.getDriftReport", + "summary": "Get machine drift report", + "description": "Returns a single drift report by ID.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Drift report ID" + }, + "required": true, + "description": "Drift report ID", + "name": "report_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Machine drift report", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DriftReport" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}/suspension_events": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.listSuspensionEvents", + "summary": "List machine suspension events", + "description": "Lists historical suspension events for the machine. Events record suspend, resume, expiry, and snapshot-cost details for audit and billing reports.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "manual", + "downgrade" + ] + }, + "required": false, + "name": "reason", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Suspension event list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionEventList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/machines/{id}/suspension_events/{event_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Machines" + ], + "operationId": "machines.getSuspensionEvent", + "summary": "Get machine suspension event", + "description": "Returns a single suspension event for a machine, including snapshot reference, cost, lifecycle state, and timing details.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "event_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Suspension event", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionEvent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/compute_configs": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "ComputeConfigs" + ], + "operationId": "computeConfigs.create", + "summary": "Create compute config", + "description": "Creates a compute config row.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "provider": { + "type": "string", + "enum": [ + "hcloud" + ] + }, + "provider_config": { + "type": "object", + "properties": { + "region": { + "type": "string", + "minLength": 1 + }, + "image": { + "type": "string", + "minLength": 1 + }, + "machine_type_filter": { + "type": "string" + } + }, + "required": [ + "region", + "image" + ] + }, + "credential_scope": { + "$ref": "#/components/schemas/CredentialScope" + } + }, + "required": [ + "name", + "provider", + "provider_config", + "credential_scope" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Compute config created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "compute.ui.listComputeConfigsForApi" + }, + "tags": [ + "ComputeConfigs" + ], + "operationId": "computeConfigs.list", + "summary": "List compute configs", + "description": "Lists compute configs in the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic" + }, + "required": false, + "name": "view", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Compute config list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfigList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/compute_configs/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "ComputeConfigs" + ], + "operationId": "computeConfigs.get", + "summary": "Get compute config", + "description": "Returns a compute config by ID.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Compute config details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "ComputeConfigs" + ], + "operationId": "computeConfigs.update", + "summary": "Update compute config", + "description": "Updates mutable fields of a compute config.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "provider_config": { + "type": "object", + "properties": { + "region": { + "type": "string", + "minLength": 1 + }, + "image": { + "type": "string", + "minLength": 1 + }, + "machine_type_filter": { + "type": "string" + } + } + }, + "credential_scope": { + "$ref": "#/components/schemas/CredentialScope" + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Compute config updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "ComputeConfigs" + ], + "operationId": "computeConfigs.delete", + "summary": "Delete compute config", + "description": "Deletes a compute config.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Compute config deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputeConfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "products.list", + "tags": [ + "Products" + ], + "summary": "List products in workspace", + "description": "Returns all products belonging to the workspace specified in the workspace context.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "products.create", + "tags": [ + "Products" + ], + "summary": "Create product", + "description": "Creates a Product backed by an existing Package and package version pin. Package source import belongs to the Packages API.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProductBody" + } + } + } + }, + "responses": { + "201": { + "description": "Product created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products:dashboardList": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "product.ui.listDashboardProductsForApi" + }, + "operationId": "products.listDashboard", + "tags": [ + "Products" + ], + "summary": "List dashboard products in workspace", + "description": "Returns product rows shaped for the dashboard product catalog, including target counts.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Dashboard product list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardProductList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products:marketplaceList": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "product.ui.getMarketplaceProductsForUi" + }, + "operationId": "products.listMarketplace", + "tags": [ + "Products" + ], + "summary": "List marketplace products", + "description": "Returns product rows shaped for the marketplace catalog.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Marketplace product list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarketplaceProductList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "product.ui.getProductForApi" + }, + "operationId": "products.get", + "tags": [ + "Products" + ], + "summary": "Get product details", + "description": "Returns product metadata including the backing Package and marketplace settings.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID", + "example": "prod_j572abc..." + }, + "required": true, + "description": "Product ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Product details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "products.update", + "tags": [ + "Products" + ], + "summary": "Update product", + "description": "Updates Product metadata, marketplace listing state, and the package version pin for future offers and installs.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID", + "example": "prod_j572abc..." + }, + "required": true, + "description": "Product ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProductBody" + } + } + } + }, + "responses": { + "200": { + "description": "Product updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products/{id}:marketplace": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "product.ui.getPublicProductForUi" + }, + "operationId": "products.getMarketplace", + "tags": [ + "Products" + ], + "summary": "Get marketplace product", + "description": "Returns product detail shaped for the marketplace product page.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID", + "example": "prod_j572abc..." + }, + "required": true, + "description": "Product ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Marketplace product detail", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarketplaceProductDetail" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products/{id}:archive": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "products.archive", + "tags": [ + "Products" + ], + "summary": "Archive product", + "description": "Archives the product and removes it from active marketplace listings. The row persists with state `archived` for audit/history/revenue-attribution. Active installs and past orders are unaffected; backing packages remain independently managed and unchanged. Dashboard callers can still render historical product context.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID", + "example": "prod_j572abc..." + }, + "required": true, + "description": "Product ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArchiveProductBody" + } + } + } + }, + "responses": { + "200": { + "description": "Product archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/products/{id}:unarchive": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "products.unarchive", + "tags": [ + "Products" + ], + "summary": "Unarchive product", + "description": "Restores a previously-archived product to `active`. The row remains in place and history is preserved. Active installs continue; dependent offers stay untouched unless separately unarchived.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Product ID", + "example": "prod_j572abc..." + }, + "required": true, + "description": "Product ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Product unarchived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offer_channels": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "offerChannels.create", + "tags": [ + "Offer Channels" + ], + "summary": "Create offer channel", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOfferChannelBody" + } + } + } + }, + "responses": { + "201": { + "description": "Offer channel created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferChannel" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "TRUSTED_PARTNER", + "x-platform-live": { + "visibility": "TRUSTED_PARTNER", + "transport": "convex", + "convexQuery": "offers.ui.listOfferChannelsForApi" + }, + "operationId": "offerChannels.list", + "tags": [ + "Offer Channels" + ], + "summary": "List offer channels", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": false, + "name": "product_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Offer channels", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferChannelList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offer_channels/{id}": { + "get": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "offerChannels.get", + "tags": [ + "Offer Channels" + ], + "summary": "Get offer channel", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Offer channel", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferChannel" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offer_channels/{id}:archive": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "offerChannels.archive", + "tags": [ + "Offer Channels" + ], + "summary": "Archive offer channel", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Offer channel archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferChannel" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/channel_policies": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "channelPolicies.create", + "tags": [ + "Channel Policies" + ], + "summary": "Create channel policy", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChannelPolicyBody" + } + } + } + }, + "responses": { + "201": { + "description": "Channel policy created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelPolicy" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "TRUSTED_PARTNER", + "x-platform-live": { + "visibility": "TRUSTED_PARTNER", + "transport": "convex", + "convexQuery": "offers.ui.listChannelPoliciesForApi" + }, + "operationId": "channelPolicies.list", + "tags": [ + "Channel Policies" + ], + "summary": "List channel policies", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "offer_channel", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Channel policies", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelPolicyList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/channel_policies/{id}": { + "get": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "channelPolicies.get", + "tags": [ + "Channel Policies" + ], + "summary": "Get channel policy", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel policy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelPolicy" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/channel_policies/{id}:approve": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "channelPolicies.approve", + "tags": [ + "Channel Policies" + ], + "summary": "Approve channel policy", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Channel policy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelPolicy" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/channel_policies/{id}:activate": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "channelPolicies.activate", + "tags": [ + "Channel Policies" + ], + "summary": "Activate channel policy", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Channel policy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelPolicy" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/channel_policies/{id}:archive": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "channelPolicies.archive", + "tags": [ + "Channel Policies" + ], + "summary": "Archive channel policy", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Channel policy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelPolicy" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "TRUSTED_PARTNER", + "transport": "convex", + "convexQuery": "offers.ui.listMyWorkspaceOffers" + }, + "operationId": "offers.list", + "tags": [ + "Offers" + ], + "summary": "List offers in workspace", + "description": "Returns offers belonging to the workspace specified in the workspace context, newest first.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": false, + "name": "product_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of offers", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "offers.create", + "tags": [ + "Offers" + ], + "summary": "Create offer", + "description": "Creates an Offer for a product or a specific package version. When `product_id` is supplied without `package_version_id`, the server resolves the product’s current package version pin, validates `field_values` against that resolved version’s input schema, and stores the concrete package version on the Offer. Customers reach the Offer at `/i/` to start an install. When `allowed_emails` is non-empty, only those email addresses can use the Offer; when empty or omitted, any authenticated customer can.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOfferBody" + } + } + } + }, + "responses": { + "201": { + "description": "Offer created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferCreated" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "offers.get", + "tags": [ + "Offers" + ], + "summary": "Get offer details", + "description": "Returns the full offer record including pre-fill values and email allowlist. Caller must be a member of the offer’s workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID", + "example": "offer_j572abc..." + }, + "required": true, + "description": "Offer ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Offer details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Offer" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers:preview": { + "post": { + "x-platform-visibility": "TRUSTED_PARTNER", + "operationId": "offers.preview", + "tags": [ + "Offers" + ], + "summary": "Preview offer policy", + "description": "Resolves an offer request against the active Offer Channel policy without creating an offer.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewOfferBody" + } + } + } + }, + "responses": { + "200": { + "description": "Offer policy preview", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OfferPolicySnapshot" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers/{id}:approve": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "offers.approve", + "tags": [ + "Offers" + ], + "summary": "Approve offer", + "description": "Approves a pending channel-backed offer and freezes its requested policy snapshot as the approved effective policy snapshot.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID", + "example": "offer_j572abc..." + }, + "required": true, + "description": "Offer ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Offer approved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Offer" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers/{id}:reject": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "offers.reject", + "tags": [ + "Offers" + ], + "summary": "Reject offer", + "description": "Rejects a pending channel-backed offer. Rejected offers keep their requested policy snapshot but cannot receive an approved effective snapshot.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID", + "example": "offer_j572abc..." + }, + "required": true, + "description": "Offer ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Offer rejected", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Offer" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers:resolve": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "offers.resolve", + "tags": [ + "Offers" + ], + "summary": "Resolve offer by short hash", + "description": "Resolves an offer from the customer-clicked URL `/i/`. Anonymous callers receive the publicly-safe subset of fields needed to render the landing page (product name, logo, seller name, status, tier). Authenticated callers whose verified email matches the offer's allowlist additionally receive pre-fill values and other workspace-private fields. Authenticated callers whose email is not on the allowlist receive 403.", + "security": [], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Offer short hash from the customer-clicked URL" + }, + "required": true, + "description": "Offer short hash from the customer-clicked URL", + "name": "short_hash", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Offer resolved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Offer" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers/{id}:archive": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "offers.archive", + "tags": [ + "Offers" + ], + "summary": "Archive offer", + "description": "Archives the offer and blocks new redemptions. The offer row remains for history and audit; callers receive the full Offer with `status: \"archived\"`. Idempotent: already-archived offers return unchanged. If-Match is required for optimistic concurrency.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID", + "example": "offer_j572abc..." + }, + "required": true, + "description": "Offer ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Offer archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Offer" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers/{id}:unarchive": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "offers.unarchive", + "tags": [ + "Offers" + ], + "summary": "Unarchive offer", + "description": "Reverts a previously-archived offer back to `active`. Idempotent: already-active offers return unchanged. Does not auto-cascade to dependents or previously-archived child references.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Offer ID", + "example": "offer_j572abc..." + }, + "required": true, + "description": "Offer ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Offer unarchived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Offer" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/offers/{offer}/order_drafts": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.create", + "tags": [ + "Order Drafts" + ], + "summary": "Create order draft", + "description": "Creates a customer wizard session (OrderDraft) for the parent offer. The caller is the customer; their authenticated user becomes the draft's owner. Each idempotent create call returns the same draft for the same Idempotency-Key. Concurrency limits and email-allowlist gates apply per the offer's configuration; failures map to 403 (forbidden) or 422 (offer not redeemable).", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Parent offer ID", + "example": "offer_j572abc..." + }, + "required": true, + "description": "Parent offer ID", + "name": "offer", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "201": { + "description": "Order draft started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraft" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.list", + "tags": [ + "Order Drafts" + ], + "summary": "List order drafts", + "description": "Returns order drafts for one offer. `?offer=` is required in v1; `?status=` can further filter by wizard phase. With a workspace context (token-implied or `Akua-Context`), only workspace-member-visible drafts are returned and `field_values` is omitted.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Filter by offer ID", + "example": "offer_j572abc123def456" + }, + "required": false, + "description": "Filter by offer ID", + "name": "offer", + "in": "query" + }, + { + "schema": { + "$ref": "#/components/schemas/OrderDraftStatus" + }, + "required": false, + "description": "Wizard phase. Driven by the order draft actor; mirrored on every patch to the row so reactive UIs render one column. `done` and `terminated` are terminal.", + "name": "status", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of order drafts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraftList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts:workspaceList": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "orders.ui.listMyWorkspaceOrders" + }, + "operationId": "orderDrafts.listWorkspace", + "tags": [ + "Order Drafts" + ], + "summary": "List workspace order drafts", + "description": "Returns order drafts for offers in the selected workspace. Intended for dashboard live reads.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of workspace order drafts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraftList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "orders.ui.getMyOrderDraft" + }, + "operationId": "orderDrafts.get", + "tags": [ + "Order Drafts" + ], + "summary": "Get order draft details", + "description": "Returns the order draft row. The order draft’s own customer sees the full record including `field_values`; workspace members of the parent offer see the row with `field_values` omitted.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Order draft details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraft" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}:cancel": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.cancel", + "tags": [ + "Order Drafts" + ], + "summary": "Cancel order draft", + "description": "Terminates an in-flight order draft, returning the updated record. Allowed for the order draft’s own customer or any member of the parent offer’s workspace. Idempotent — cancelling a terminated order draft returns it unchanged. Allocated cluster resources are released and any in-flight install workflow is terminated; previously-completed work is NOT undone.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Order draft cancelled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraft" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}:claim": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.claim", + "tags": [ + "Order Drafts" + ], + "summary": "Claim order draft", + "description": "Binds the calling authenticated user to an anonymous order draft using a one-time claim token (R13 + AIP-147 INPUT_ONLY).", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClaimOrderDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Order draft claimed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraft" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}:selectWorkspace": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.selectWorkspace", + "tags": [ + "Order Drafts" + ], + "summary": "Select order workspace", + "description": "Selects the customer workspace for an order draft, or creates a new workspace for the order. This advances the draft from workspace selection to compute allocation.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SelectOrderDraftWorkspaceBody" + } + } + } + }, + "responses": { + "200": { + "description": "Workspace selected", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraft" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}:submitConfiguration": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.submitConfigure", + "tags": [ + "Order Drafts" + ], + "summary": "Submit configure values", + "description": "Persists the customer’s configure-form values on the order draft and advances it to the payment phase, returning the updated record. Values are validated against the package version’s schema.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitConfigureOrderDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Configure submitted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraft" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}:createWorkerBootstrap": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.createWorkerBootstrap", + "tags": [ + "Order Drafts" + ], + "summary": "Create order draft worker bootstrap", + "description": "Creates a short-lived worker bootstrap token and renders command/cloud-init data for the cluster allocated to this order draft. Only valid while the draft is waiting for compute bootstrap.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ttl_seconds": { + "type": "integer", + "minimum": 60, + "maximum": 86400 + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Worker bootstrap data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraftWorkerBootstrap" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}/checkout_sessions": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.createCheckoutSession", + "tags": [ + "Order Drafts" + ], + "summary": "Create order draft checkout session", + "description": "Creates a Stripe Checkout Session for the current order-draft payment revision, or returns the existing open session when it still has enough remaining lifetime. Stale sessions are expired and superseded before a replacement is created.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "201": { + "description": "Checkout session created or reused", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderDraftCheckoutSession" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.listCheckoutSessions", + "tags": [ + "Order Drafts" + ], + "summary": "List order draft checkout sessions", + "description": "Returns historical checkout session rows for the order draft (current and past) for resume/audit workflows.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of checkout sessions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckoutSessionList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/order_drafts/{id}/checkout_sessions/{chk_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "orderDrafts.getCheckoutSession", + "tags": [ + "Order Drafts" + ], + "summary": "Get order draft checkout session", + "description": "Returns one historical checkout session by ID, including the current session state.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order draft ID", + "example": "odft_j572abc..." + }, + "required": true, + "description": "Order draft ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Checkout session ID", + "example": "chk_abcdefghijk..." + }, + "required": true, + "description": "Checkout session ID", + "name": "chk_id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Checkout session details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckoutSession" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/orders/{order}/deliveries/{delivery}:removeDemoCleanup": { + "post": { + "x-platform-visibility": "ADMIN", + "operationId": "orderDrafts.removeDemoCleanup", + "tags": [ + "Order Drafts" + ], + "summary": "Remove demo cleanup after platform approval", + "description": "Removes scheduled cleanup from a non-billable demo/test order delivery after platform approval. This is an admin-only conversion hook; sellers and customers cannot remove cleanup unilaterally.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Committed order ID" + }, + "required": true, + "description": "Committed order ID", + "name": "order", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Order delivery ID" + }, + "required": true, + "description": "Order delivery ID", + "name": "delivery", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveDemoCleanupAfterPlatformApprovalBody" + } + } + } + }, + "responses": { + "200": { + "description": "Demo cleanup removed from the order and delivery", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DemoCleanupRemoval" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/entitlements": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "entitlements.list", + "tags": [ + "Entitlements" + ], + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "workspace.ui.listEffectiveEntitlementsForApi" + }, + "summary": "List entitlements", + "description": "Returns active effective entitlements visible to the authenticated caller.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Filter entitlements to one workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Filter entitlements to one workspace.", + "name": "workspace", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "description": "Filter entitlements to one feature set, such as `compute`." + }, + "required": false, + "description": "Filter entitlements to one feature set, such as `compute`.", + "name": "feature_set", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "Filter entitlements to one exact feature key, such as `compute.max_clusters`." + }, + "required": false, + "description": "Filter entitlements to one exact feature key, such as `compute.max_clusters`.", + "name": "feature", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Entitlement list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EntitlementList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/operations": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "operations.ui.listOperationsForWorkspaceForApi" + }, + "operationId": "operations.list", + "tags": [ + "Operations" + ], + "summary": "List operations", + "description": "Workspace-scoped list of long-running operations, newest first. Without filters returns every operation in the workspace; with `?owner_type=install&owner_id=` narrows to a single entity.\n\nState for in-flight operations is eventually consistent — may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-platform-query-contracts": [ + { + "kind": "requires-together", + "fields": [ + "owner_type", + "owner_id" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "install", + "repository_change_request", + "repository", + "workspace", + "machine", + "cluster", + "package" + ] + }, + "required": false, + "name": "owner_type", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Required when `owner_type` is set. Ignored otherwise." + }, + "required": false, + "description": "Required when `owner_type` is set. Ignored otherwise.", + "name": "owner_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of operations (without per-step detail)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationList" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/operations/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "operations.get", + "tags": [ + "Operations" + ], + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "operations.ui.getOperationWithStepsForApi" + }, + "summary": "Get operation details + steps", + "description": "Returns the operation row plus its per-step progress events. Clients poll this endpoint while `done` is false; when `done` flips true, `response` carries the typed result (`SUCCEEDED`) or `error.message` carries the failure reason. Prefer `POST /v1/operations/{id}:wait` for sync \"wait until done\" semantics — it long-polls server-side instead of asking the client to tight-poll.\n\nState for in-flight operations is eventually consistent — may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Operation ID. Prefixed form `op_` is canonical; bare IDs accepted during transition.", + "example": "op_j572abc..." + }, + "required": true, + "description": "Operation ID. Prefixed form `op_` is canonical; bare IDs accepted during transition.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Operation details (with steps)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/operations/{id}:wait": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "operations.wait", + "tags": [ + "Operations" + ], + "summary": "Wait for an operation to reach a terminal state", + "description": "Long-polls server-side until the operation reaches a terminal state (`SUCCEEDED`, `FAILED`, `CANCELLED`) or the timeout elapses. Returns the latest `Operation` either way — check `done` to distinguish.\n\nServer-side this is a live subscription on the operation row, not a polling loop, so the response fires within milliseconds of the workflow reaching its terminal state.\n\nState for in-flight operations is eventually consistent — may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Operation ID. Prefixed form `op_` is canonical; bare IDs accepted during transition.", + "example": "op_j572abc..." + }, + "required": true, + "description": "Operation ID. Prefixed form `op_` is canonical; bare IDs accepted during transition.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 60, + "description": "Max seconds to wait for the operation to reach a terminal state. Default 30, max 60." + }, + "required": false, + "description": "Max seconds to wait for the operation to reach a terminal state. Default 30, max 60.", + "name": "timeout", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Operation in its latest known state (terminal or still running on timeout)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/operations/{id}:cancel": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "operations.cancel", + "tags": [ + "Operations" + ], + "summary": "Request operation cancellation", + "description": "Requests cancellation of an in-flight operation. Cancellation is asynchronous: successful requests return the current operation envelope while the worker drains the current step before settling into a terminal result. Replaying the request with the same Idempotency-Key is supported. If the operation has already reached a terminal state, cancellation is rejected with Unprocessable Entity.\n\nWhen accepted, the operation is not cancelled instantly; it transitions through the normal cancellation flow and may still report progress for a short time.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Operation ID. Prefixed form `op_` is canonical; bare IDs accepted during transition.", + "example": "op_j572abc..." + }, + "required": true, + "description": "Operation ID. Prefixed form `op_` is canonical; bare IDs accepted during transition.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Optional optimistic concurrency token for clients that track the latest operation revision.", + "example": "WzQ1Njc=" + }, + "required": false, + "description": "Optional optimistic concurrency token for clients that track the latest operation revision.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Cancellation requested; operation transition is in progress", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs:dashboardList": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "install.listDashboardInstallsForApi" + }, + "operationId": "installs.listDashboard", + "tags": [ + "Installs" + ], + "summary": "List dashboard installs", + "description": "Returns standalone install rows shaped for the dashboard applications table.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Dashboard install list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardInstallList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}:dashboard": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "install.getDashboardInstallForApi" + }, + "operationId": "installs.getDashboard", + "tags": [ + "Installs" + ], + "summary": "Get dashboard install detail", + "description": "Returns an install detail row shaped for the dashboard install pages.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Dashboard install detail", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardInstallDetail" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "install.listInstallsForApi" + }, + "operationId": "installs.list", + "tags": [ + "Installs" + ], + "summary": "List installs", + "description": "Lists installs in the current workspace. With `product_id`, lists installs attributed to that product for product-owner support visibility.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": false, + "name": "product_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Installs list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.create", + "tags": [ + "Installs" + ], + "summary": "Create install", + "description": "Creates a product install via a long-running saga that may run for several minutes. Returns an Operation envelope to poll for progress.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateInstallBody" + } + } + } + }, + "responses": { + "202": { + "description": "Install workflow started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.get", + "tags": [ + "Installs" + ], + "summary": "Get install details", + "description": "Returns current install metadata.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Install details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Install" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.delete", + "tags": [ + "Installs" + ], + "summary": "Delete install", + "description": "Deletes an install and cascades resource cleanup asynchronously. Returns an Operation envelope to poll for progress.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Delete workflow started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/domain_settings": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "cloudflare.ui.getInstallDomainSettingsForApi" + }, + "operationId": "installs.getDomainSettings", + "tags": [ + "Installs" + ], + "summary": "Get install domain settings", + "description": "Returns dashboard domain-routing settings for one install.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Install domain settings", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallDomainSettings" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/renders": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.createRender", + "tags": [ + "Installs" + ], + "summary": "Create install render", + "description": "Starts a render attempt and records the resulting render artifact metadata.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateInstallRenderBody" + } + } + } + }, + "responses": { + "201": { + "description": "Render artifact created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallRender" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.listRenders", + "tags": [ + "Installs" + ], + "summary": "List install renders", + "description": "Lists render artifacts for an install.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Install renders", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallRenderList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/renders/{render_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.getRender", + "tags": [ + "Installs" + ], + "summary": "Get install render", + "description": "Returns a single render artifact.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Render ID", + "example": "rnd_j572abc..." + }, + "required": true, + "description": "Render ID", + "name": "render_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Render artifact", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallRender" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/status": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.getStatus", + "tags": [ + "Installs" + ], + "summary": "Get install status", + "description": "Returns the live install deploy status for dashboards and health checks.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Install status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallStatus" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/pods": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.listPods", + "tags": [ + "Installs" + ], + "summary": "List install pods", + "description": "Returns current pod names and containers for the install.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Install pods", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PodList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/logs": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "installs.getLogs", + "tags": [ + "Installs" + ], + "summary": "Stream install logs", + "description": "Streams log output for an install via Server-Sent Events. Use `Accept: text/event-stream`.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID", + "example": "inst_j572abc123def456" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 253, + "description": "Pod name (all pods if omitted)" + }, + "required": false, + "description": "Pod name (all pods if omitted)", + "name": "pod", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 253, + "description": "Container name" + }, + "required": false, + "description": "Container name", + "name": "container", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "nullable": true, + "default": true, + "description": "Follow log output" + }, + "required": false, + "description": "Follow log output", + "name": "follow", + "in": "query" + }, + { + "schema": { + "type": "integer", + "nullable": true, + "description": "Lines to tail" + }, + "required": false, + "description": "Lines to tail", + "name": "tail", + "in": "query" + }, + { + "schema": { + "type": "integer", + "nullable": true, + "default": 0, + "description": "Only return logs newer than this many seconds" + }, + "required": false, + "description": "Only return logs newer than this many seconds", + "name": "since_seconds", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Log stream", + "content": { + "text/event-stream": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "packages.ui.listMyWorkspacePackagesForApi" + }, + "operationId": "packages.list", + "tags": [ + "Packages" + ], + "summary": "List packages", + "description": "Returns all packages in the active workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic", + "description": "Controls whether sensitive source provenance is included. `basic` omits `composed_from_sources`." + }, + "required": false, + "description": "Controls whether sensitive source provenance is included. `basic` omits `composed_from_sources`.", + "name": "view", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of packages", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Packages" + ], + "operationId": "packages.create", + "summary": "Create package", + "description": "Creates a package from one OCI Helm source as a long-running operation.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePackageBody" + } + } + } + }, + "responses": { + "202": { + "description": "Package creation accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageOperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages:withVersions": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "packages.ui.listMyWorkspacePackagesWithVersionsForApi" + }, + "operationId": "packages.listWithVersions", + "tags": [ + "Packages" + ], + "summary": "List packages with versions", + "description": "Returns dashboard package choices with newest-first version summaries for create flows.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Packages with version summaries", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageWithVersionsList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages:inventory": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "packages.ui.listMyWorkspacePackageInventoryForApi" + }, + "operationId": "packages.listInventory", + "tags": [ + "Packages" + ], + "summary": "List package inventory", + "description": "Returns dashboard package inventory rows with source metadata and newest version summaries.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Package inventory rows", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageInventoryList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "packages.get", + "tags": [ + "Packages" + ], + "summary": "Get package details", + "description": "Returns a single package and the `latest_version_id` pointer for this workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic", + "description": "Controls whether sensitive source provenance is included. `basic` omits `composed_from_sources`." + }, + "required": false, + "description": "Controls whether sensitive source provenance is included. `basic` omits `composed_from_sources`.", + "name": "view", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Package details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Package" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Packages" + ], + "operationId": "packages.delete", + "summary": "Delete package", + "description": "Deletes a Package and its PackageVersions only when no Product references the Package and no Install references any PackageVersion.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Package deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages/{id}:detail": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "packages.ui.getMyPackageDetailForApi" + }, + "operationId": "packages.getDetail", + "tags": [ + "Packages" + ], + "summary": "Get package detail", + "description": "Returns dashboard package detail with version history and input schemas.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Package ID" + }, + "required": true, + "description": "Package ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Package detail or null when missing", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageDetailResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages/{id}/versions": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "packages.listVersions", + "tags": [ + "Packages" + ], + "summary": "List package versions", + "description": "Returns published versions of a package, newest first.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of package versions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageVersionList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "packages.createVersion", + "tags": [ + "Packages" + ], + "summary": "Create package version", + "description": "Registers an immutable version for an existing OCI-backed package. Akua verifies the supplied version metadata against the published artifact before durable registration. Requires published Package import access. Hosted packages publish versions through the package creation workflow.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Package ID", + "example": "pkg_j572abc123def456" + }, + "required": true, + "description": "Package ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePackageVersionBody" + } + } + } + }, + "responses": { + "201": { + "description": "Package version created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageVersion" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages/{id}/versions/{version_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "packages.getVersion", + "tags": [ + "Packages" + ], + "summary": "Get package version details", + "description": "Returns a single version entry for a package.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "version_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Package version details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageVersion" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages/{id}/versions/{version_id}/inputs": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "packages.ui.getMyPackageVersionInputSchemaForApi" + }, + "operationId": "packages.getVersionInputs", + "tags": [ + "Packages" + ], + "summary": "Get package version input schema", + "description": "Returns the version input schema used by the install wizard, typically generated JSON Schema.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55 + }, + "required": true, + "name": "version_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Package version input schema", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageVersionInputs" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages/artifacthub/{package_id}/versions/{version}/values_schema": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "packages.getArtifacthubValuesSchema", + "tags": [ + "Packages" + ], + "summary": "Resolve Artifact Hub chart values + schema", + "description": "Fetches a chart's values from Artifact Hub and returns them with a JSON Schema — the chart's published schema (when present) merged over a schema inferred from the values, so the editor always has defaults to show.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Artifact Hub package id", + "example": "a1b2c3d4-..." + }, + "required": true, + "description": "Artifact Hub package id", + "name": "package_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Chart version", + "example": "1.2.3" + }, + "required": true, + "description": "Chart version", + "name": "version", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "Also fetch the chart's published values-schema and merge it in" + }, + "required": false, + "description": "Also fetch the chart's published values-schema and merge it in", + "name": "include_schema", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Resolved chart values + schema", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageArtifacthubValuesSchema" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/packages:import": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Packages" + ], + "operationId": "packages.importPublished", + "summary": "Import published package", + "description": "Imports a published OCI-backed Akua package and registers its first immutable version. Akua verifies the supplied version metadata against the published artifact before durable registration. Requires published Package import access.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportPackageBody" + } + } + } + }, + "responses": { + "201": { + "description": "Package imported", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Package" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "workspace.ui.listWorkspacesForApi" + }, + "operationId": "workspaces.list", + "tags": [ + "Workspaces" + ], + "summary": "List workspaces", + "description": "Returns all workspaces visible to the authenticated user.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Workspace list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.create", + "tags": [ + "Workspaces" + ], + "summary": "Create workspace", + "description": "Creates a workspace for the authenticated user.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "slug": { + "type": "string", + "minLength": 3, + "maxLength": 39 + }, + "icon": { + "type": "string", + "maxLength": 256, + "format": "uri", + "x-platform-visibility": "INTERNAL" + }, + "auto_select": { + "type": "boolean", + "x-platform-visibility": "INTERNAL" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Workspace created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.get", + "tags": [ + "Workspaces" + ], + "summary": "Get workspace", + "description": "Returns the details of a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Workspace details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.update", + "tags": [ + "Workspaces" + ], + "summary": "Update workspace", + "description": "Updates workspace metadata for the selected workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "slug": { + "type": "string", + "minLength": 3, + "maxLength": 39 + }, + "icon": { + "type": "string", + "maxLength": 256, + "format": "uri", + "x-platform-visibility": "INTERNAL" + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Workspace updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.delete", + "tags": [ + "Workspaces" + ], + "summary": "Delete workspace", + "description": "Asynchronously deletes a workspace and all of its workspace-owned resources.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Workspace deletion accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "504": { + "description": "Gateway timeout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/members": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.listMembers", + "tags": [ + "Workspaces" + ], + "summary": "List workspace members", + "description": "Returns the members and roles for a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Workspace members", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceMemberList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.addMember", + "tags": [ + "Workspaces" + ], + "summary": "Add workspace member", + "description": "Adds a user to a workspace with the requested role.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "description": "BetterAuth user ID of the workspace member to add", + "example": "user_abc123" + }, + "role": { + "type": "string", + "enum": [ + "admin", + "member" + ] + } + }, + "required": [ + "user_id", + "role" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Workspace member added" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/members/{userId}": { + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.updateMember", + "tags": [ + "Workspaces" + ], + "summary": "Update workspace member role", + "description": "Updates the role of a workspace member.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Member user ID" + }, + "required": true, + "description": "Member user ID", + "name": "userId", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "admin", + "member" + ] + } + }, + "required": [ + "role" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Workspace member updated" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.removeMember", + "tags": [ + "Workspaces" + ], + "summary": "Remove workspace member", + "description": "Removes a user from a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Member user ID" + }, + "required": true, + "description": "Member user ID", + "name": "userId", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Workspace member removed" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subscription": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.getSubscription", + "tags": [ + "Workspaces" + ], + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "workspace.ui.getSubscriptionForApi" + }, + "summary": "Get workspace subscription", + "description": "Returns billing subscription information for a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Workspace subscription", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceSubscription" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/access_state": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.getAccessState", + "tags": [ + "Workspaces" + ], + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "workspace.ui.getAccessStateForApi" + }, + "summary": "Get workspace access state", + "description": "Returns whether the workspace is currently accessible and why.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Workspace access state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceAccessState" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subscription:cancel": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.cancelSubscription", + "tags": [ + "Workspaces" + ], + "summary": "Cancel workspace subscription", + "description": "Cancels or schedules cancellation for a workspace subscription.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "effective": { + "type": "string", + "enum": [ + "period_end" + ] + } + }, + "required": [ + "effective" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "202": { + "description": "Subscription cancellation accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subscription:reactivate": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.reactivateSubscription", + "tags": [ + "Workspaces" + ], + "summary": "Reactivate workspace subscription", + "description": "Reactivates a workspace subscription and clears cancellation schedule.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "additionalProperties": false + } + } + } + }, + "responses": { + "202": { + "description": "Workspace subscription reactivation accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subscription:changeTier": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.changeSubscriptionTier", + "tags": [ + "Workspaces" + ], + "summary": "Change workspace subscription tier", + "description": "Schedules a subscription tier change for the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tier": { + "type": "string" + } + }, + "required": [ + "tier" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "202": { + "description": "Tier change accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationEnvelope" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subscription/change_requests": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.listSubscriptionChangeRequests", + "tags": [ + "Workspaces" + ], + "summary": "List subscription change requests", + "description": "Returns subscription tier change requests for workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Subscription change requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionChangeRequestList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subscription/change_requests/{req_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaces.getSubscriptionChangeRequest", + "tags": [ + "Workspaces" + ], + "summary": "Get subscription change request", + "description": "Returns one subscription change request record.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Subscription change request ID" + }, + "required": true, + "description": "Subscription change request ID", + "name": "req_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Subscription change request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionChangeRequest" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/api_tokens": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "apiTokens.create", + "tags": [ + "API Tokens" + ], + "summary": "Create an API token", + "description": "Creates a workspace API token. The full plaintext token is returned in the response and never shown again - store it securely.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiTokenRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Token created. The `token` field is shown only once.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatedApiToken" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "apiToken.ui.listForApi" + }, + "operationId": "apiTokens.list", + "tags": [ + "API Tokens" + ], + "summary": "List API tokens", + "description": "Returns metadata for the workspace's API tokens. Full token values are never shown after creation.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of tokens", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiTokenList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/api_tokens/{id}": { + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "apiTokens.revoke", + "tags": [ + "API Tokens" + ], + "summary": "Revoke an API token", + "description": "Revokes a workspace API token. The token immediately stops authenticating requests.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Token ID. Prefixed form `tok_` is canonical.", + "example": "tok_j572abc123def456" + }, + "required": true, + "description": "Token ID. Prefixed form `tok_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Token revoked" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repositories": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "repository.ui.listRepositoriesForApi" + }, + "operationId": "repositories.list", + "tags": [ + "Repositories" + ], + "summary": "List repositories in workspace", + "description": "Lists repositories visible in the workspace. Filterable by `purpose` (deploy / package / repository_change_request). Wire IDs prefixed `repo_...`. Cursor-paginated.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "deploy", + "package", + "repository_change_request" + ], + "description": "Filter by repository purpose (deploy / package / repository_change_request)" + }, + "required": false, + "description": "Filter by repository purpose (deploy / package / repository_change_request)", + "name": "purpose", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic", + "description": "Controls inclusion of implementation detail fields." + }, + "required": false, + "description": "Controls inclusion of implementation detail fields.", + "name": "view", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of repositories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repositories/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "repositories.get", + "tags": [ + "Repositories" + ], + "summary": "Get repository details", + "description": "Returns a single repository as a discriminated union per `purpose`; the shape varies by lifecycle.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Repository ID" + }, + "required": true, + "description": "Repository ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "basic", + "full" + ], + "default": "basic", + "description": "Basic view is the default; full includes implementation details like render hashes and implementation refs." + }, + "required": false, + "description": "Basic view is the default; full includes implementation details like render hashes and implementation refs.", + "name": "view", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Repository details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Repository" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/installation_url": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "github.createInstallationUrl", + "tags": [ + "Github" + ], + "summary": "Create a GitHub App installation URL", + "description": "Generates a GitHub App installation URL with a one-time state for the workspace. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubCreateInstallationUrlBody" + } + } + } + }, + "responses": { + "200": { + "description": "Installation URL", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubInstallationUrl" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/installations/{installation_id}/repositories": { + "get": { + "x-platform-visibility": "INTERNAL", + "operationId": "github.listInstallationRepositories", + "tags": [ + "Github" + ], + "summary": "List repositories for a GitHub App installation", + "description": "Lists repositories accessible to the installation. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "GitHub App installation ID", + "example": 12345678 + }, + "required": true, + "description": "GitHub App installation ID", + "name": "installation_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Repositories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubRepoList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/installations": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "gitapp.ui.listAppInstallationsForWorkspaceForApi" + }, + "operationId": "github.listInstallations", + "tags": [ + "Github" + ], + "summary": "List GitHub App installations for a workspace", + "description": "Returns GitHub App installations available to the current workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "GitHub App installations", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubAppInstallationList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/workflow_prs/{repository_id}": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "gitapp.ui.getWorkflowPullRequestForApi" + }, + "operationId": "github.getWorkflowPullRequest", + "tags": [ + "Github" + ], + "summary": "Get workflow setup pull request for a repository", + "description": "Returns the workflow setup pull request for a repository, if one exists.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": true, + "name": "repository_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Workflow setup pull request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubWorkflowPrGet" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/installations/{installation_id}/repositories/{repository_id}/workflow_runs": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "gitapp.ui.listImageBuildsForRepositoryForApi" + }, + "operationId": "github.listWorkflowRuns", + "tags": [ + "Github" + ], + "summary": "List GitHub workflow runs for a repository", + "description": "Lists GitHub workflow runs captured for a repository.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": true, + "name": "installation_id", + "in": "path" + }, + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": true, + "name": "repository_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "GitHub workflow runs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubWorkflowRunList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/package_permissions:check": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "github.checkPackagePermissions", + "tags": [ + "Github" + ], + "summary": "Check GHCR package write-permission warnings for a repository", + "description": "Returns a warning + fix URL if the repository may lack GHCR package write access. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubCheckPackagePermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permission check result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubPackagePermissions" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/workflow_prs": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "github.createWorkflowPr", + "tags": [ + "Github" + ], + "summary": "Open a PR adding the build workflow to a repository", + "description": "Creates a branch and pull request adding the Akua build workflow file. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubCreateWorkflowPrBody" + } + } + } + }, + "responses": { + "200": { + "description": "Created PR", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubWorkflowPrCreated" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/github/installations:verify": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "github.verifyInstallation", + "tags": [ + "Github" + ], + "summary": "Verify a GitHub App installation", + "description": "Completes the GitHub App installation OAuth callback: exchanges the code, verifies the installation belongs to the user, persists it against the one-time state, and returns the post-install redirect URL. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubVerifyInstallationBody" + } + } + } + }, + "responses": { + "200": { + "description": "Installation verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GithubVerifyInstallationResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.create", + "tags": [ + "Secrets" + ], + "summary": "Create secret", + "description": "Creates a workspace-scoped Secret with metadata and the first version. The plaintext value is consumed and never echoed.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSecretBody" + } + } + } + }, + "responses": { + "201": { + "description": "Secret created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Secret" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "secrets.ui.listSecretsForApi" + }, + "operationId": "secrets.list", + "tags": [ + "Secrets" + ], + "summary": "List secrets", + "description": "Lists workspace secrets. Metadata only; plaintext values are never returned.", + "security": [ + { + "BearerAuth": [ + "secrets:read" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by secret kind.", + "example": "generic" + }, + "required": false, + "description": "Filter by secret kind.", + "name": "kind", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "secrets.ui.getSecretForApi" + }, + "operationId": "secrets.get", + "tags": [ + "Secrets" + ], + "summary": "Get secret", + "description": "Returns secret metadata. Plaintext values are never returned.", + "security": [ + { + "BearerAuth": [ + "secrets:read" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Secret" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.update", + "tags": [ + "Secrets" + ], + "summary": "Update secret", + "description": "Updates secret metadata only. Rotate values with POST /secrets/{id}/versions.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSecretBody" + } + } + } + }, + "responses": { + "200": { + "description": "Secret updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Secret" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.delete", + "tags": [ + "Secrets" + ], + "summary": "Delete secret", + "description": "Soft-deletes a secret and keeps version payloads recoverable until purge_at. Use force=true to immediately destroy version payloads.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "boolean", + "nullable": true, + "default": false + }, + "required": false, + "name": "force", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Secret deleted" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}:undelete": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Secrets" + ], + "operationId": "secrets.undelete", + "summary": "Restore a soft-deleted secret", + "description": "Restores a Secret that was soft-deleted via DELETE /v1/secrets/{id}, provided the call happens before its purge_at deadline. The Secret returns to state=active and its retained version payloads become accessible again. Returns 409 ABORTED on stale If-Match. Returns 404 if the secret was hard-deleted (force=true on DELETE) or has been purged.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret restored", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Secret" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/validate_token": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.validateToken", + "tags": [ + "Secrets" + ], + "summary": "Validate a provider token", + "description": "Probes a customer-supplied cloud-provider API token with a cheap read-only call to confirm it authenticates, without storing it. Use before creating a `cloud_provider/*` secret.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateProviderTokenBody" + } + } + } + }, + "responses": { + "200": { + "description": "Validation result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateProviderTokenResult" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}/versions": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.createVersion", + "tags": [ + "Secrets" + ], + "summary": "Create secret version", + "description": "Appends a new immutable SecretVersion. Plaintext is never echoed.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSecretVersionBody" + } + } + } + }, + "responses": { + "201": { + "description": "Secret version created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretVersion" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "secrets.ui.listSecretVersionsForApi" + }, + "operationId": "secrets.listVersions", + "tags": [ + "Secrets" + ], + "summary": "List secret versions", + "description": "Lists secret versions. Metadata only; plaintext values are never returned.", + "security": [ + { + "BearerAuth": [ + "secrets:read" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "enabled", + "disabled", + "destroyed" + ], + "description": "Filter by secret version state." + }, + "required": false, + "description": "Filter by secret version state.", + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret version list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretVersionList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}/versions/{vid}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.getVersion", + "tags": [ + "Secrets" + ], + "summary": "Get secret version", + "description": "Returns metadata for one secret version. Plaintext is never returned.", + "security": [ + { + "BearerAuth": [ + "secrets:read" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "example": "secv_j572abc123def456" + }, + "required": true, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "name": "vid", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret version metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretVersion" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}/versions/{vid}:enable": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Secrets" + ], + "operationId": "secrets.enableVersion", + "summary": "Enable a disabled secret version", + "description": "Re-enables a disabled SecretVersion. The newly-enabled version becomes eligible for `:access` calls again. Idempotent: enabling an already-enabled version returns 200 with no state change. Returns 409 ABORTED with a stale-revision hint if If-Match mismatches. Returns 409 if the version has been destroyed (irreversible).", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "example": "secv_j572abc123def456" + }, + "required": true, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "name": "vid", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Version enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretVersion" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}/versions/{vid}:disable": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.disableVersion", + "tags": [ + "Secrets" + ], + "summary": "Disable secret version", + "description": "Marks a secret version as disabled.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "example": "secv_j572abc123def456" + }, + "required": true, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "name": "vid", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret version disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretVersion" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}/versions/{vid}:destroy": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.destroyVersion", + "tags": [ + "Secrets" + ], + "summary": "Destroy secret version", + "description": "Irreversibly destroys a secret version payload and keeps metadata for audit.", + "security": [ + { + "BearerAuth": [ + "secrets:write" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "example": "secv_j572abc123def456" + }, + "required": true, + "description": "SecretVersion ID. Prefixed form `secv_` is canonical.", + "name": "vid", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret version destroyed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretVersion" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/secrets/{id}/versions/{vid}:access": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "secrets.accessVersion", + "tags": [ + "Secrets" + ], + "summary": "Access secret version plaintext", + "description": "Returns the plaintext value for an active secret version and writes an audit-log entry. Soft-deleted secrets return 404 until restored with :undelete.", + "security": [ + { + "BearerAuth": [ + "secrets:access" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "example": "sec_j572abc123def456" + }, + "required": true, + "description": "Secret ID. Prefixed form `sec_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "description": "SecretVersion ID (`secv_`), `latest`, or a version alias such as `current`.", + "example": "latest" + }, + "required": true, + "description": "SecretVersion ID (`secv_`), `latest`, or a version alias such as `current`.", + "name": "vid", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Secret plaintext", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretPlaintext" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "410": { + "description": "Gone", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/stripe_account": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.createStripeAccount", + "tags": [ + "Stripe" + ], + "summary": "Create connected Stripe account", + "description": "Creates a connected payment-provider account for the workspace, or returns the existing one. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStripeAccountBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connected Stripe account created or resolved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StripeAccountCreated" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.getStripeAccountStatus", + "tags": [ + "Stripe" + ], + "summary": "Get connected Stripe account status", + "description": "Returns the live charges and payouts status of the workspace connected payment-provider account. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Connected Stripe account status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StripeAccountStatus" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.cancelStripeOnboarding", + "tags": [ + "Stripe" + ], + "summary": "Cancel connected Stripe account onboarding", + "description": "Cancels onboarding and removes the workspace connected payment-provider account. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Onboarding cancelled" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/stripe_account:createLink": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.createStripeAccountLink", + "tags": [ + "Stripe" + ], + "summary": "Create connected Stripe account link", + "description": "Creates an onboarding link the seller follows to onboard or update their connected payment-provider account. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "format": "uri", + "description": "Request origin used to derive default connected-account return and refresh URLs when the body omits them.", + "example": "https://akua.dev" + }, + "required": true, + "description": "Request origin used to derive default connected-account return and refresh URLs when the body omits them.", + "name": "origin", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStripeAccountLinkBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connected Stripe account link created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StripeAccountLinkCreated" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/stripe_account:createSession": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.createStripeAccountSession", + "tags": [ + "Stripe" + ], + "summary": "Create connected Stripe account session", + "description": "Creates an embedded-UI session for the workspace connected payment-provider account, returning the client secret used to mount embedded components. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStripeAccountSessionBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connected Stripe account session created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StripeAccountSessionCreated" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/stripe_products": { + "get": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.getStripeProducts", + "tags": [ + "Stripe" + ], + "summary": "List connected Stripe account products", + "description": "Returns the catalog of the workspace connected payment-provider account, grouped by product, for the dashboard pricing picker. Returns an empty catalog when no account is connected. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Connected Stripe account catalog grouped by product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceStripeProducts" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspace_subscription:createUpgradeCheckout": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.createUpgradeCheckout", + "tags": [ + "Stripe" + ], + "summary": "Create Pro upgrade checkout session", + "description": "Creates a payment-provider Checkout session for upgrading the workspace to the Pro plan. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUpgradeCheckoutBody" + } + } + } + }, + "responses": { + "201": { + "description": "Pro upgrade checkout session created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpgradeCheckoutCreated" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/billing_portal_session": { + "post": { + "x-platform-visibility": "INTERNAL", + "operationId": "workspaces.createBillingPortalSession", + "tags": [ + "Stripe" + ], + "summary": "Create billing portal session", + "description": "Creates a payment-provider Customer Portal session for managing the workspace Pro subscription. Dashboard-only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBillingPortalSessionBody" + } + } + } + }, + "responses": { + "201": { + "description": "Billing portal session created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BillingPortalSessionCreated" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.list", + "summary": "List clusters", + "description": "Lists clusters visible to the authenticated workspace owner.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Cluster list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClusterList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.create", + "summary": "Create cluster", + "description": "Creates a managed cluster and returns an async Operation envelope. State for in-flight operations is eventually consistent and may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "description": "Display name for the cluster." + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "network_profile": { + "type": "string", + "enum": [ + "linux_cilium", + "mixed_os_calico" + ], + "default": "linux_cilium", + "description": "Immutable networking profile for managed KaaS clusters. Defaults to `linux_cilium`; Windows workers require `mixed_os_calico`." + } + }, + "required": [ + "name", + "region_id" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "202": { + "description": "Cluster create operation accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters:dashboardList": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "cluster.ui.listDashboardClustersForApi" + }, + "tags": [ + "Clusters" + ], + "operationId": "clusters.listDashboard", + "summary": "List dashboard clusters", + "description": "Returns clusters shaped for the dashboard clusters page.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Dashboard cluster list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardClusterList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.get", + "summary": "Get cluster", + "description": "Gets a cluster by id.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Cluster ID." + }, + "required": true, + "description": "Cluster ID.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Cluster details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cluster" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.update", + "summary": "Update cluster", + "description": "Updates editable cluster fields.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "provider": { + "type": "string", + "enum": [ + "managed_kaas", + "imported_byoc" + ], + "description": "Cluster control-plane family: managed (`managed_kaas`) vs imported self-managed (`imported_byoc`)." + }, + "kubeconfig": { + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Cluster updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cluster" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.delete", + "summary": "Delete cluster", + "description": "Tears down the cluster and all of its owned resources. Returns an Operation envelope; the actual teardown happens asynchronously. Caller must be a workspace owner.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Delete initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters:import": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.import", + "summary": "Import cluster", + "description": "Imports an existing cluster from kubeconfig.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "region_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "kubeconfig": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "region_id", + "kubeconfig" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Cluster imported", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cluster" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/capabilities": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.getCapabilities", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "cluster.ui.getClusterCapabilitiesForApi" + }, + "summary": "Get cluster capabilities", + "description": "Gets the last observed Kubernetes capability snapshot for a cluster.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Cluster ID." + }, + "required": true, + "description": "Cluster ID.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Cluster capabilities", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClusterCapabilities" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/capabilities:refresh": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.refreshCapabilities", + "summary": "Refresh cluster capabilities", + "description": "Refreshes observed cluster capability facts. The API returns an Operation envelope because cluster inspection runs asynchronously.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Refresh initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}:suspend": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.suspend", + "summary": "Suspend cluster", + "description": "Suspends a running cluster. The API returns an Operation envelope because teardown and drain are asynchronous.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Suspend initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}:resume": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.resume", + "summary": "Resume cluster", + "description": "Resumes a suspended cluster and returns an async Operation envelope.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Resume initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/kubeconfig": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.getKubeconfig", + "summary": "Get cluster kubeconfig", + "description": "Returns cluster admin kubeconfig for workspace owners. R6 deliberate divergence retained with an audit-log requirement.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Cluster kubeconfig", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Kubeconfig" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/kube_proxy/{path:*}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.proxyKube", + "summary": "Proxy cluster API", + "description": "Proxy kube-apiserver traffic through the public API. `path:*` is forwarded verbatim to upstream.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Kube API path forwarded verbatim" + }, + "required": true, + "description": "Kube API path forwarded verbatim", + "name": "path", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Kube API response passthrough" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}:exec": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.exec", + "summary": "Execute command in cluster", + "description": "Runs a structured command in a pod and returns the result inline. No LRO wrapper by design.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecBody" + } + } + } + }, + "responses": { + "200": { + "description": "Command output", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecResult" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/worker_bootstraps": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.createWorkerBootstrap", + "summary": "Create worker bootstrap", + "description": "Issues a new worker-bootstrap row and returns its metadata.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ttl_seconds": { + "type": "integer", + "minimum": 60, + "maximum": 86400, + "description": "Token TTL in seconds (optional)." + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Worker bootstrap created", + "headers": { + "Location": { + "description": "Location of the created worker bootstrap.", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkerBootstrap" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "cluster.ui.listWorkerBootstrapsByClusterForApi" + }, + "tags": [ + "Clusters" + ], + "operationId": "clusters.listWorkerBootstraps", + "summary": "List cluster worker bootstraps", + "description": "Lists worker-bootstrap tokens for the cluster. Cursor-paginated. Includes revoked / expired tokens by default — filter via the `status` query when implemented.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Worker bootstraps page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkerBootstrapList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/worker_bootstraps/{wbs_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.getWorkerBootstrap", + "summary": "Get cluster worker bootstrap", + "description": "Returns a single worker-bootstrap token by ID, including its current status and expiry timestamp.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "wbs_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Worker bootstrap", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkerBootstrap" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/clusters/{id}/worker_bootstraps/{wbs_id}:revoke": { + "post": { + "x-platform-visibility": "PUBLIC", + "tags": [ + "Clusters" + ], + "operationId": "clusters.revokeWorkerBootstrap", + "summary": "Revoke worker bootstrap", + "description": "Starts an asynchronous revoke of a worker bootstrap token. The bootstrap is soft-revoked immediately; k0s token invalidation completes when the managed control plane is reachable.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "wbs_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Revoke initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/user/admin_status": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "auth.getAdminStatus", + "tags": [ + "Auth" + ], + "summary": "Get current admin status", + "description": "Returns whether the authenticated user has platform administrator access in the dashboard.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Current admin status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminStatus" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/dashboard/counts": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "ui.getDashboardCountsForApi" + }, + "operationId": "dashboard.getCounts", + "tags": [ + "Dashboard Overview" + ], + "summary": "Get dashboard counts", + "description": "Returns aggregate dashboard counts for the selected workspace scope.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Dashboard counts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardCounts" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/organizations": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "organization.ui.listMyOrganizationsForApi" + }, + "operationId": "organizations.list", + "tags": [ + "Organizations" + ], + "summary": "List organizations", + "description": "Lists all organizations the authenticated user belongs to.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of organizations", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.create", + "tags": [ + "Organizations" + ], + "summary": "Create organization", + "description": "Creates a new organization. The authenticated user becomes the initial owner.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Organization created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Organization" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/organizations/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.get", + "tags": [ + "Organizations" + ], + "summary": "Get organization details", + "description": "Returns details for an organization the authenticated user belongs to.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Organization details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Organization" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.update", + "tags": [ + "Organizations" + ], + "summary": "Update organization", + "description": "Updates profile fields on an organization. Requires owner or admin role in the organization.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Organization updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationOk" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.delete", + "tags": [ + "Organizations" + ], + "summary": "Delete organization", + "description": "Deletes an organization after validating membership, workspace ownership, and owner protection.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Organization deleted" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/organizations/{id}/members": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "organization.ui.listMembersForApi" + }, + "operationId": "organizations.listMembers", + "tags": [ + "Organizations" + ], + "summary": "List organization members", + "description": "Lists every member of the organization. Requires membership in the organization.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of members", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationMemberList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.addMember", + "tags": [ + "Organizations" + ], + "summary": "Add organization member", + "description": "Adds a user to the organization with the supplied role (defaults to `member`). Requires owner or admin role.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationAddMemberRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Member added", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationOk" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/organizations/{id}/members/{userId}": { + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.updateMemberRole", + "tags": [ + "Organizations" + ], + "summary": "Update member role", + "description": "Updates the role of an existing member. Only the organization's owner may change roles.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "description": "User ID of the member whose role is being updated", + "example": "user_abc123" + }, + "required": true, + "description": "User ID of the member whose role is being updated", + "name": "userId", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationUpdateMemberRoleRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Role updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationOk" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "organizations.removeMember", + "tags": [ + "Organizations" + ], + "summary": "Remove organization member", + "description": "Removes a member from the organization. Self-removal is always allowed; removing other users requires owner or admin role. The last owner cannot be removed.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "description": "User ID of the member being removed", + "example": "user_abc123" + }, + "required": true, + "description": "User ID of the member being removed", + "name": "userId", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Member removed" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/organizations/{id}/workspaces": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "organization.ui.listManagedWorkspacesForApi" + }, + "operationId": "organizations.listManagedWorkspaces", + "tags": [ + "Organizations" + ], + "summary": "List managed workspaces", + "description": "Lists workspaces managed by this organization. Requires membership in the organization.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "example": "org_j572abc123def456" + }, + "required": true, + "description": "Organization ID. Prefixed form `org_` is canonical.", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of managed workspaces", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedWorkspaceList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/notifications": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "notifications.ui.listNotificationsForApi" + }, + "operationId": "notifications.list", + "tags": [ + "Notifications" + ], + "summary": "List recent notifications", + "description": "Returns the authenticated user's most recent in-app notifications (max 50, newest first). Pass `unread=true` to filter to unread notifications only.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When set to `true`, only unread notifications are returned." + }, + "required": false, + "description": "When set to `true`, only unread notifications are returned.", + "name": "unread", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Recent notifications (max 50)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/notifications/unread_count": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "notifications.ui.getUnreadCountForApi" + }, + "operationId": "notifications.getUnreadCount", + "tags": [ + "Notifications" + ], + "summary": "Count unread notifications", + "description": "Returns the number of unread in-app notifications for the authenticated user.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Unread count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnreadCount" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/notifications/{id}/read": { + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "notifications.markRead", + "tags": [ + "Notifications" + ], + "summary": "Mark a notification as read", + "description": "Marks a single notification as read. Idempotent: calls for already-read or unowned notifications succeed without effect.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Notification ID. Prefixed form `ntf_` is canonical.", + "example": "ntf_j572abc123def456" + }, + "required": true, + "description": "Notification ID. Prefixed form `ntf_` is canonical.", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Marked as read" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/notifications/mark_all_read": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "notifications.markAllRead", + "tags": [ + "Notifications" + ], + "summary": "Mark all notifications as read", + "description": "Marks every unread in-app notification for the authenticated user as read. Idempotent.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "204": { + "description": "All marked as read" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/quotas": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "quotas.list", + "tags": [ + "Quotas" + ], + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "quota.ui.listQuotaUsageForApi" + }, + "summary": "List quota usage for the authenticated user", + "description": "Returns current usage and limits for all quota metrics. Allocation and rate quotas are per-user across all workspaces. Concurrency quotas are per-cluster — pass `cluster_id` to include them.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Cluster ID to include concurrency quotas" + }, + "required": false, + "description": "Cluster ID to include concurrency quotas", + "name": "cluster_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Quota info for all metrics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuotaInfoList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/quotas/{metric}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "quotas.get", + "tags": [ + "Quotas" + ], + "summary": "Get quota usage for a specific metric", + "description": "Returns current usage and limit for a single quota metric. The metric must be URL-encoded (e.g. `compute%2Fmachines`).", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "example": "compute/machines", + "description": "Quota metric (URL-encoded service/resource)." + }, + "required": true, + "description": "Quota metric (URL-encoded service/resource).", + "name": "metric", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Quota info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuotaInfo" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/regions": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "cluster.ui.listRegionsForApi" + }, + "operationId": "regions.list", + "tags": [ + "Regions" + ], + "summary": "List regions in workspace", + "description": "Returns all regions belonging to the workspace specified in the workspace context.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of regions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegionList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "regions.create", + "tags": [ + "Regions" + ], + "summary": "Create region", + "description": "Creates a named region in the workspace. Regions group clusters geographically for marketplace display.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "example": "us-east-1" + }, + "icon": { + "type": "string", + "maxLength": 256, + "format": "uri", + "description": "Icon URL" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Region created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Region" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/regions:dashboardList": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "cluster.ui.listDashboardRegionsForApi" + }, + "operationId": "regions.listDashboard", + "tags": [ + "Regions" + ], + "summary": "List dashboard regions", + "description": "Returns workspace regions with dashboard-only cluster pool health.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Dashboard region list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardRegionList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/registry_connections": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "registry.listCredentials", + "tags": [ + "Registry" + ], + "summary": "List registry credentials", + "description": "Returns credentials for the workspace. Credential secrets are never exposed.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistryCredentialList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "registry.createCredential", + "tags": [ + "Registry" + ], + "summary": "Create registry credential", + "description": "Adds a registry credential to the workspace for OCI proxy authentication.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "example": "GitHub Container Registry" + }, + "registry_url": { + "type": "string", + "minLength": 1, + "maxLength": 2048, + "example": "ghcr.io" + }, + "type": { + "type": "string", + "enum": [ + "basic", + "token", + "oauth" + ], + "description": "Authentication scheme used to talk to the upstream registry." + }, + "credentials": { + "type": "object", + "properties": { + "username": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Username for basic auth" + }, + "password": { + "type": "string", + "minLength": 1, + "maxLength": 500, + "description": "Password for basic auth" + }, + "token": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "Bearer token for token auth" + }, + "client_id": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Client ID for OAuth" + }, + "client_secret": { + "type": "string", + "minLength": 1, + "maxLength": 500, + "description": "Client secret for OAuth" + }, + "token_url": { + "type": "string", + "minLength": 1, + "maxLength": 2048, + "description": "Token endpoint URL for OAuth" + } + }, + "description": "Auth credentials (type-dependent)" + } + }, + "required": [ + "name", + "registry_url", + "type", + "credentials" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Credential created" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/registry_connections/{id}": { + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "registry.deleteCredential", + "tags": [ + "Registry" + ], + "summary": "Delete registry credential", + "description": "Permanently removes a registry credential. Active installs using this credential may lose pull access.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Registry connection ID. Prefixed form `rcon_` is canonical.", + "example": "rcon_j572abc123def456" + }, + "required": true, + "description": "Registry connection ID. Prefixed form `rcon_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Credential deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/registry/insights/stats": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "registry.ui.getRegistryStatsForApi" + }, + "operationId": "registry.getStats", + "tags": [ + "Registry" + ], + "summary": "Get registry stats", + "description": "Returns aggregate pull, auth, registry, and latency stats for a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "24h", + "7d", + "30d" + ], + "description": "Time window used to aggregate registry audit events." + }, + "required": true, + "description": "Time window used to aggregate registry audit events.", + "name": "period", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Registry stats", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistryStats" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/registry/insights/activity": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "registry.ui.getRegistryActivityForApi" + }, + "operationId": "registry.getActivity", + "tags": [ + "Registry" + ], + "summary": "Get registry pull activity", + "description": "Returns pull activity buckets for charting registry proxy usage.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "24h", + "7d", + "30d" + ], + "description": "Time window used to aggregate registry audit events." + }, + "required": true, + "description": "Time window used to aggregate registry audit events.", + "name": "period", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Registry activity buckets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistryActivityResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/registry/insights/audit_logs": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "registry.ui.listRegistryAuditLogsForApi" + }, + "operationId": "registry.listAuditLogs", + "tags": [ + "Registry" + ], + "summary": "List registry audit logs", + "description": "Returns recent registry proxy audit log entries for a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "number", + "minimum": 1, + "maximum": 100 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Recent registry audit logs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistryAuditLogList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/registry/insights/errors": { + "get": { + "x-platform-visibility": "INTERNAL", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "registry.ui.getRegistryErrorsForApi" + }, + "operationId": "registry.getErrors", + "tags": [ + "Registry" + ], + "summary": "Get registry errors", + "description": "Returns the top registry proxy error messages for a workspace and period.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "24h", + "7d", + "30d" + ], + "description": "Time window used to aggregate registry audit events." + }, + "required": true, + "description": "Time window used to aggregate registry audit events.", + "name": "period", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Top registry errors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistryErrorList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repository_change_requests": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "repositoryChangeRequests.create", + "tags": [ + "Repository change requests" + ], + "summary": "Create repository change request", + "description": "Creates a fork-backed repository change request. Fork write credentials are minted separately.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRepositoryChangeRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "Repository change request created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRepositoryChangeRequestResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "repositoryChangeRequests.ui.listMyWorkspaceRepositoryChangeRequests" + }, + "operationId": "repositoryChangeRequests.list", + "tags": [ + "Repository change requests" + ], + "summary": "List repository change requests", + "description": "Lists fork-backed repository change requests in the active workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-platform-query-contracts": [ + { + "kind": "at-most-one", + "fields": [ + "parent_repository", + "fork_repository" + ] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "AWAITING_CHANGES", + "VALIDATING", + "READY", + "ACCEPTING", + "ACCEPTED", + "REJECTED", + "WITHDRAWN", + "EXPIRED", + "FAILED" + ], + "description": "Filter by lifecycle state" + }, + "required": false, + "description": "Filter by lifecycle state", + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Filter to change requests targeting this parent repository", + "example": "repo_j572parentrepo001" + }, + "required": false, + "description": "Filter to change requests targeting this parent repository", + "name": "parent_repository", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Filter to the change request backed by this fork repository", + "example": "repo_j572forkrepo001" + }, + "required": false, + "description": "Filter to the change request backed by this fork repository", + "name": "fork_repository", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Filter to change requests created by this agent", + "example": "agt_j572agent001" + }, + "required": false, + "description": "Filter to change requests created by this agent", + "name": "agent", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Repository change request list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryChangeRequestList" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repository_change_requests/{id}:createToken": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "repositoryChangeRequests.createToken", + "tags": [ + "Repository change requests" + ], + "summary": "Create repository change request token", + "description": "Mints short-lived credentials for pushing changes to the fork repository.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRepositoryChangeRequestTokenBody" + } + } + } + }, + "responses": { + "201": { + "description": "Repository change request token created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRepositoryChangeRequestTokenResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repository_change_requests/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "repositoryChangeRequests.ui.getMyRepositoryChangeRequestForApi" + }, + "operationId": "repositoryChangeRequests.get", + "tags": [ + "Repository change requests" + ], + "summary": "Get repository change request", + "description": "Returns one fork-backed repository change request.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Repository change request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryChangeRequest" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repository_change_requests/{id}:accept": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "repositoryChangeRequests.accept", + "tags": [ + "Repository change requests" + ], + "summary": "Accept repository change request", + "description": "Validates and merges a repository change request into its parent repository.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Repository change request accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcceptRepositoryChangeRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repository_change_requests/{id}:reject": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "repositoryChangeRequests.reject", + "tags": [ + "Repository change requests" + ], + "summary": "Reject repository change request", + "description": "Rejects a repository change request and records the reason.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectRepositoryChangeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "Repository change request rejected", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectRepositoryChangeRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/repository_change_requests/{id}:withdraw": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "repositoryChangeRequests.withdraw", + "tags": [ + "Repository change requests" + ], + "summary": "Withdraw repository change request", + "description": "Withdraws an editable repository change request and purges its fork.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Repository change request withdrawn", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WithdrawRepositoryChangeRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agents": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agents.create", + "tags": [ + "Agents" + ], + "summary": "Create agent", + "description": "Creates a durable workspace-scoped agent identity.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "instructions": { + "type": "string", + "minLength": 1, + "maxLength": 20000 + }, + "capabilities": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "CHAT", + "CODING", + "AMBIENT" + ] + }, + "minItems": 1, + "maxItems": 10 + }, + "ambient": { + "$ref": "#/components/schemas/AgentAmbientConfig" + }, + "model_policy": { + "$ref": "#/components/schemas/AgentModelPolicy" + } + }, + "required": [ + "name", + "instructions", + "capabilities" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Agent created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listAgents" + }, + "operationId": "agents.list", + "tags": [ + "Agents" + ], + "summary": "List agents", + "description": "Lists agents in the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agents/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agents.get", + "tags": [ + "Agents" + ], + "summary": "Get agent", + "description": "Gets one agent.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "agents.update", + "tags": [ + "Agents" + ], + "summary": "Update agent", + "description": "Updates mutable agent configuration. Lifecycle state changes use archive.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "instructions": { + "type": "string", + "minLength": 1, + "maxLength": 20000 + }, + "capabilities": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "CHAT", + "CODING", + "AMBIENT" + ] + }, + "minItems": 1, + "maxItems": 10 + }, + "ambient": { + "$ref": "#/components/schemas/AgentAmbientConfig" + }, + "model_policy": { + "$ref": "#/components/schemas/AgentModelPolicy" + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Agent updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "agents.archive", + "tags": [ + "Agents" + ], + "summary": "Archive agent", + "description": "Archives an agent and stops future ambient triggers.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agents/{id}:enable": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agents.enable", + "tags": [ + "Agents" + ], + "summary": "Enable agent", + "description": "Re-enables an archived agent so it can receive sessions and ambient triggers.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_skills": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listAgentSkills" + }, + "operationId": "agentSkills.list", + "tags": [ + "Agent skills" + ], + "summary": "List agent skills", + "description": "Lists published agent skills visible to the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent skill list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkillList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_skills/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentSkills.get", + "tags": [ + "Agent skills" + ], + "summary": "Get agent skill", + "description": "Gets one agent skill.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent skill", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkill" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_templates": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "agent.ui.listAgentTemplatesForApi" + }, + "operationId": "agentTemplates.list", + "tags": [ + "Agent templates" + ], + "summary": "List agent templates", + "description": "Lists platform-curated agent templates visible to the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent template list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTemplateList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_templates/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentTemplates.get", + "tags": [ + "Agent templates" + ], + "summary": "Get agent template", + "description": "Gets one platform-curated agent template.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent template", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTemplate" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_preferences": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "PUBLIC", + "transport": "convex", + "convexQuery": "agent.ui.getAgentPreferencesForApi" + }, + "operationId": "agentPreferences.get", + "tags": [ + "Agent preferences" + ], + "summary": "Get agent preferences", + "description": "Gets the current user's workspace-scoped agent preferences.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent preferences", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentPreference" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentPreferences.update", + "tags": [ + "Agent preferences" + ], + "summary": "Update agent preferences", + "description": "Updates the current user's workspace-scoped agent preferences.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "communication_profile": { + "type": "string", + "enum": [ + "BEGINNER", + "INTERMEDIATE", + "ADVANCED", + "EXPERT", + "ADAPTIVE" + ] + }, + "learning_mode_enabled": { + "type": "boolean" + }, + "seen_concepts": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "maxItems": 200 + } + }, + "required": [ + "communication_profile", + "learning_mode_enabled", + "seen_concepts" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Agent preferences updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentPreference" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agents/sandbox_operations_summary": { + "get": { + "x-platform-visibility": "INTERNAL", + "operationId": "agents.getSandboxOperationsSummary", + "tags": [ + "Agents" + ], + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.getSandboxOperationsSummaryForApi" + }, + "summary": "Get sandbox operations summary", + "description": "Returns workspace-scoped sandbox operational metrics for the dashboard.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Sandbox operations summary", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxOperationsSummary" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_sessions": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentSessions.create", + "tags": [ + "Agent sessions" + ], + "summary": "Create agent session", + "description": "Creates a durable workspace-scoped session for an agent.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "title": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "communication_profile": { + "type": "string", + "enum": [ + "BEGINNER", + "INTERMEDIATE", + "ADVANCED", + "EXPERT", + "ADAPTIVE" + ], + "default": "ADAPTIVE" + }, + "parent_session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "forked_from_session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "spawned_by_turn_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "agent_role": { + "type": "string", + "minLength": 1, + "maxLength": 80 + } + }, + "required": [ + "agent_id" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Agent session created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listAgentSessions" + }, + "operationId": "agentSessions.list", + "tags": [ + "Agent sessions" + ], + "summary": "List agent sessions", + "description": "Lists agent sessions in the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "parent_session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "forked_from_session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "spawned_by_turn", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "required": false, + "name": "agent_role", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent session list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSessionList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_sessions:detectConflicts": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentSessions.detectConflicts", + "tags": [ + "Agent sessions" + ], + "summary": "Detect agent work conflicts", + "description": "Finds active agent sessions that have already referenced the same repository, install, cluster, or repository change request.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "repository", + "install", + "cluster", + "repository_change_request" + ] + }, + "required": true, + "name": "resource", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "required": true, + "name": "id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "exclude_session", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 20 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent work conflicts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentWorkConflictList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_sessions/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentSessions.get", + "tags": [ + "Agent sessions" + ], + "summary": "Get agent session", + "description": "Gets one agent session.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentSessions.archive", + "tags": [ + "Agent sessions" + ], + "summary": "Archive agent session", + "description": "Archives an agent session and requests runtime cleanup.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent session archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_sessions/{id}:setRetention": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentSessions.setRetention", + "tags": [ + "Agent sessions" + ], + "summary": "Set agent session retention", + "description": "Updates retained filesystem policy for an agent session.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetAgentSessionRetentionBody" + } + } + } + }, + "responses": { + "200": { + "description": "Agent session retention updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_turns": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentTurns.create", + "tags": [ + "Agent turns" + ], + "summary": "Submit agent turn", + "description": "Submits one instruction to an agent session.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "message": { + "type": "string", + "minLength": 1, + "maxLength": 50000 + }, + "runtime_hint": { + "type": "string", + "enum": [ + "AUTO", + "CODE_MODE", + "RETAINED_RUNTIME" + ], + "default": "AUTO" + } + }, + "required": [ + "session_id", + "message" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "Agent turn submitted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTurn" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listAgentTurns" + }, + "operationId": "agentTurns.list", + "tags": [ + "Agent turns" + ], + "summary": "List agent turns", + "description": "Lists agent turns in the workspace or one session.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "session", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent turn list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTurnList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_turns/{id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentTurns.get", + "tags": [ + "Agent turns" + ], + "summary": "Get agent turn", + "description": "Gets one agent turn.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Agent turn", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTurn" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_turns/{id}:cancel": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentTurns.cancel", + "tags": [ + "Agent turns" + ], + "summary": "Cancel agent turn", + "description": "Cancels a running or queued agent turn.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "example": "create-prod-2026-05-07" + }, + "required": false, + "description": "Caller-supplied idempotency key. Repeated requests with the same key return the existing resource instead of creating a duplicate. Safe to retry after a timed-out or interrupted request.", + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent turn cancelled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTurn" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_turns/{id}:emit": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentTurns.emit", + "tags": [ + "Agent turns" + ], + "summary": "Emit agent turn event", + "description": "Emits a constrained event intent for a running agent turn.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "message" + ] + }, + "data": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "assistant", + "system" + ] + }, + "content": { + "type": "string", + "minLength": 1, + "maxLength": 50000 + } + }, + "required": [ + "role", + "content" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "widget" + ] + }, + "data": { + "type": "object", + "properties": { + "widget_type": { + "type": "string", + "enum": [ + "approval_card", + "choice_card", + "form", + "secret_input", + "status_card", + "docs_card", + "diagram", + "navigation_hint", + "repository_change_request_review" + ] + }, + "schema_version": { + "type": "integer", + "minimum": 1 + }, + "title": { + "type": "string", + "maxLength": 200 + }, + "summary": { + "type": "string", + "maxLength": 5000 + }, + "resource_refs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 80 + } + }, + "required": [ + "resource", + "id" + ], + "additionalProperties": false + }, + "maxItems": 20, + "default": [] + }, + "reactive_bindings": { + "type": "array", + "items": { + "nullable": true + }, + "maxItems": 20, + "default": [] + }, + "actions": { + "type": "array", + "items": { + "nullable": true + }, + "maxItems": 20, + "default": [] + } + }, + "required": [ + "widget_type", + "schema_version" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "artifact" + ] + }, + "data": { + "type": "object", + "properties": { + "artifact_type": { + "type": "string", + "enum": [ + "diff", + "patch", + "log_bundle", + "summary", + "file", + "resource_ref" + ] + }, + "title": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "resource_refs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 80 + } + }, + "required": [ + "resource", + "id" + ], + "additionalProperties": false + }, + "maxItems": 20, + "default": [] + } + }, + "required": [ + "artifact_type", + "title" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "progress" + ] + }, + "data": { + "type": "object", + "properties": { + "state": { + "type": "string", + "enum": [ + "QUEUED", + "RUNNING", + "WAITING", + "COMPLETED", + "FAILED" + ] + }, + "message": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + } + }, + "required": [ + "state", + "message" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "execution_environment" + ] + }, + "data": { + "type": "object", + "properties": { + "state": { + "type": "string", + "enum": [ + "STARTED", + "STOPPED", + "RESUMED", + "DELETED", + "FAILED" + ] + }, + "message": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + }, + "sandbox_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + } + }, + "required": [ + "state", + "message" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "approval_request" + ] + }, + "data": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 5000 + }, + "actions": { + "type": "array", + "items": { + "nullable": true + }, + "maxItems": 20, + "default": [] + } + }, + "required": [ + "title", + "summary" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "handoff_summary" + ] + }, + "data": { + "type": "object", + "properties": { + "child_session_id": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 5000 + }, + "touched_resource_refs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resource": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 80 + } + }, + "required": [ + "resource", + "id" + ], + "additionalProperties": false + }, + "maxItems": 50, + "default": [] + }, + "decision_points": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "maxItems": 20, + "default": [] + }, + "recommended_next_step": { + "type": "string", + "minLength": 1, + "maxLength": 1000 + } + }, + "required": [ + "child_session_id", + "summary" + ], + "additionalProperties": false + } + }, + "required": [ + "type", + "data" + ], + "additionalProperties": false + } + ] + } + } + } + }, + "responses": { + "201": { + "description": "Agent event authored", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentEvent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_provider_exchanges": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listAgentProviderExchanges" + }, + "operationId": "agentProviderExchanges.list", + "tags": [ + "Agent provider exchanges" + ], + "summary": "List agent provider exchanges", + "description": "Lists redacted provider proxy request and response metadata for one agent turn.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "turn", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent provider exchange list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentProviderExchangeList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_events:stream": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "agentEvents.stream", + "tags": [ + "Agent events" + ], + "summary": "Stream agent events", + "description": "Streams normalized agent events as Server-Sent Events.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "turn", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "parent_session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "forked_from_session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "spawned_by_turn", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "required": false, + "name": "agent_role", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "nullable": true, + "default": false + }, + "required": false, + "name": "follow", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "after", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent event stream (text/event-stream)" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/agent_events": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listLiveEvents" + }, + "operationId": "agentEvents.list", + "tags": [ + "Agent events" + ], + "summary": "List agent events", + "description": "Lists normalized events for a workspace, session, or turn.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "turn", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "parent_session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "forked_from_session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "spawned_by_turn", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "required": false, + "name": "agent_role", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "nullable": true, + "default": false + }, + "required": false, + "name": "follow", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "after", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Agent event list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentEventList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/approval_requests": { + "get": { + "x-platform-visibility": "PUBLIC", + "x-platform-live": { + "visibility": "INTERNAL", + "transport": "convex", + "convexQuery": "agent.ui.listApprovalRequests" + }, + "operationId": "approvalRequests.list", + "tags": [ + "Approval requests" + ], + "summary": "List approval requests", + "description": "Lists pending and resolved approval requests in the workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": false, + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "PENDING", + "APPROVED", + "REJECTED" + ], + "description": "Filter approval requests by lifecycle state.", + "example": "PENDING" + }, + "required": false, + "description": "Filter approval requests by lifecycle state.", + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Filter approval requests for one agent.", + "example": "agt_j572abc123def456" + }, + "required": false, + "description": "Filter approval requests for one agent.", + "name": "agent", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Filter approval requests for one agent session.", + "example": "ags_j572abc123def456" + }, + "required": false, + "description": "Filter approval requests for one agent session.", + "name": "session", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Approval request list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalRequestList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/approval_requests/{id}:resolve": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "approvalRequests.resolve", + "tags": [ + "Approval requests" + ], + "summary": "Resolve approval request", + "description": "Approves or rejects an approval request.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "decision": { + "type": "string", + "enum": [ + "APPROVE", + "REJECT" + ] + }, + "reason": { + "type": "string", + "minLength": 1, + "maxLength": 2000 + } + }, + "required": [ + "decision" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Approval request resolved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalRequest" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subdomain": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaceSubdomains.get", + "tags": [ + "Workspace subdomains" + ], + "summary": "Get workspace subdomain", + "description": "Returns the singleton workspace subdomain resource.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Workspace subdomain", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceSubdomain" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/subdomain:setName": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "workspaceSubdomains.setName", + "tags": [ + "Workspace subdomains" + ], + "summary": "Set workspace subdomain name", + "description": "Starts the workspace subdomain rename workflow.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetWorkspaceSubdomainNameBody" + } + } + } + }, + "responses": { + "202": { + "description": "Rename accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/preview_hostnames": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "previewHostnames.list", + "tags": [ + "Preview hostnames" + ], + "summary": "List preview hostnames", + "description": "Lists preview hostnames belonging to an install.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "pinned", + "floating" + ] + }, + "required": false, + "name": "binding_kind", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "required": false, + "name": "track", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "provisioning", + "active", + "evicted", + "releasing" + ], + "description": "Current preview hostname lifecycle state." + }, + "required": false, + "description": "Current preview hostname lifecycle state.", + "name": "state", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Preview hostname list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewHostnameList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/preview_hostnames/{preview_hostname_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "previewHostnames.get", + "tags": [ + "Preview hostnames" + ], + "summary": "Get preview hostname", + "description": "Returns one preview hostname belonging to an install.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Preview hostname ID" + }, + "required": true, + "description": "Preview hostname ID", + "name": "preview_hostname_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Preview hostname", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewHostname" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "previewHostnames.delete", + "tags": [ + "Preview hostnames" + ], + "summary": "Delete preview hostname", + "description": "Starts a workflow that releases a preview hostname.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Preview hostname ID" + }, + "required": true, + "description": "Preview hostname ID", + "name": "preview_hostname_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Delete accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/preview_hostnames:bindPinned": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "previewHostnames.bindPinned", + "tags": [ + "Preview hostnames" + ], + "summary": "Bind pinned preview hostname", + "description": "Starts a workflow that binds an immutable preview hostname to one render.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BindPinnedPreviewHostnameBody" + } + } + } + }, + "responses": { + "202": { + "description": "Bind accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/installs/{id}/preview_hostnames:bindFloating": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "previewHostnames.bindFloating", + "tags": [ + "Preview hostnames" + ], + "summary": "Bind floating preview hostname", + "description": "Starts a workflow that binds or rebinds a stable preview hostname track.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 55, + "description": "Install ID" + }, + "required": true, + "description": "Install ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BindFloatingPreviewHostnameBody" + } + } + } + }, + "responses": { + "202": { + "description": "Bind accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/custom_domains": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "customDomains.list", + "tags": [ + "Custom domains" + ], + "summary": "List custom domains", + "description": "Lists custom domains belonging to a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "install", + "cluster", + "external" + ] + }, + "required": false, + "name": "target_kind", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "provisioning", + "active", + "failed", + "releasing" + ] + }, + "required": false, + "name": "state", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Custom domain list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "customDomains.create", + "tags": [ + "Custom domains" + ], + "summary": "Create custom domain", + "description": "Creates a custom domain and starts routing reconciliation.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCustomDomainBody" + } + } + } + }, + "responses": { + "202": { + "description": "Create accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/workspaces/{id}/custom_domains/{custom_domain_id}": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "customDomains.get", + "tags": [ + "Custom domains" + ], + "summary": "Get custom domain", + "description": "Returns one custom domain belonging to a workspace.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Custom domain ID" + }, + "required": true, + "description": "Custom domain ID", + "name": "custom_domain_id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Custom domain", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomain" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "patch": { + "x-platform-visibility": "PUBLIC", + "operationId": "customDomains.update", + "tags": [ + "Custom domains" + ], + "summary": "Update custom domain", + "description": "Updates mutable custom domain routing settings.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Custom domain ID" + }, + "required": true, + "description": "Custom domain ID", + "name": "custom_domain_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCustomDomainBody" + } + } + } + }, + "responses": { + "202": { + "description": "Update accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "customDomains.delete", + "tags": [ + "Custom domains" + ], + "summary": "Delete custom domain", + "description": "Starts a workflow that releases a custom domain.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Workspace ID" + }, + "required": true, + "description": "Workspace ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54, + "description": "Custom domain ID" + }, + "required": true, + "description": "Custom domain ID", + "name": "custom_domain_id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "example": "42" + }, + "required": true, + "description": "The `etag` of the resource version the client last read. Required on writes when the resource exposes an `etag` field. Mismatch returns 409 `ABORTED` with the current etag in the error metadata.", + "name": "if-match", + "in": "header" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "required": true, + "name": "idempotency-key", + "in": "header" + } + ], + "responses": { + "202": { + "description": "Delete accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Operation" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/cloudflare_connections": { + "get": { + "x-platform-visibility": "PUBLIC", + "operationId": "cloudflare.listCredentials", + "tags": [ + "Cloudflare" + ], + "summary": "List Cloudflare credentials", + "description": "Returns Cloudflare credentials for the workspace. API tokens are never exposed.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Pagination cursor from a previous response's `next_cursor`." + }, + "required": false, + "description": "Pagination cursor from a previous response's `next_cursor`.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "Items per page (1-100, default 50)", + "example": 50 + }, + "required": false, + "description": "Items per page (1-100, default 50)", + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "200": { + "description": "List of Cloudflare credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CloudflareCredentialList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "cloudflare.createCredential", + "tags": [ + "Cloudflare" + ], + "summary": "Create Cloudflare credential", + "description": "Adds a Cloudflare API credential to the workspace. The API token is stored as a platform Secret and is never returned.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCloudflareCredentialBody" + } + } + } + }, + "responses": { + "201": { + "description": "Cloudflare credential created" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/cloudflare_connections/{id}": { + "delete": { + "x-platform-visibility": "PUBLIC", + "operationId": "cloudflare.deleteCredential", + "tags": [ + "Cloudflare" + ], + "summary": "Delete Cloudflare credential", + "description": "Permanently removes a Cloudflare credential. Active gateways using it must be deleted first.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 56, + "description": "Cloudflare connection ID. Prefixed form `cfcon_` is canonical.", + "example": "cfcon_j572abc123def456" + }, + "required": true, + "description": "Cloudflare connection ID. Prefixed form `cfcon_` is canonical.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "example": "ws_j572abc123def456" + }, + "required": false, + "description": "Optional workspace/scope context for the request. Carries a single workspace wire id (`ws_…`) today. Only needed for broad tokens — a workspace-owned token implies its workspace.", + "name": "akua-context", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Credential deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/access_decisions": { + "post": { + "x-platform-visibility": "PUBLIC", + "operationId": "accessDecisions.explain", + "tags": [ + "Access Decisions" + ], + "summary": "Explain an access decision", + "description": "Explains whether the authenticated requester can perform an access action and why.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExplainAccessDecisionBody" + } + } + } + }, + "responses": { + "200": { + "description": "Access decision explanation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessDecision" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/capabilities": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.listCapabilities", + "tags": [ + "Admin Access" + ], + "summary": "List admin capability projections", + "description": "Returns the platform capability catalog projection visible to admins.", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Admin capability list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminCapabilityList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/organizations": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.listOrganizations", + "tags": [ + "Admin Access" + ], + "summary": "List admin organizations", + "description": "Returns organization directory projections visible to platform administrators.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "required": false, + "name": "q", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "nullable": true + }, + "required": false, + "name": "cursor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Admin organization directory list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminDirectoryOrganizationList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/users": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.listUsers", + "tags": [ + "Admin Access" + ], + "summary": "List admin users", + "description": "Returns user directory projections visible to platform administrators, searchable by email, name, or ID.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "required": false, + "name": "q", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "nullable": true + }, + "required": false, + "name": "cursor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Admin user directory list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminDirectoryUserList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/workspaces": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.listWorkspaces", + "tags": [ + "Admin Access" + ], + "summary": "List admin workspaces", + "description": "Returns workspace directory projections visible to platform administrators.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "required": false, + "name": "q", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": false, + "name": "organization_id", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "nullable": true + }, + "required": false, + "name": "cursor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Admin workspace directory list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminDirectoryWorkspaceList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/access_overrides": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.listOverrides", + "tags": [ + "Admin Access" + ], + "summary": "List admin access overrides", + "description": "Returns feature and entitlement overrides created by platform admins.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "feature_flag", + "entitlement" + ] + }, + "required": false, + "name": "target_type", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "required": false, + "name": "key", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "global", + "organization", + "workspace" + ] + }, + "required": false, + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "nullable": true + }, + "required": false, + "name": "cursor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Admin access override list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminAccessOverrideList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.createOverride", + "tags": [ + "Admin Access" + ], + "summary": "Create an admin access override", + "description": "Creates a platform-admin override for a feature flag or entitlement.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAdminAccessOverrideBody" + } + } + } + }, + "responses": { + "201": { + "description": "Admin access override", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminAccessOverride" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/access_overrides/{id}:revoke": { + "post": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.revokeOverride", + "tags": [ + "Admin Access" + ], + "summary": "Revoke an admin access override", + "description": "Marks an admin access override as revoked while preserving audit history.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Revoked admin access override", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminAccessOverride" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/quota_overrides": { + "get": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.listQuotaOverrides", + "tags": [ + "Admin Access" + ], + "summary": "List admin quota overrides", + "description": "Returns active user and workspace quota overrides visible to platform admins.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "required": false, + "name": "metric", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "workspace" + ] + }, + "required": false, + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1 + }, + "required": false, + "name": "user_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 53 + }, + "required": false, + "name": "workspace_id", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "nullable": true + }, + "required": false, + "name": "cursor", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Admin quota override list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminQuotaOverrideList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + }, + "post": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.setQuotaOverride", + "tags": [ + "Admin Access" + ], + "summary": "Set an admin quota override", + "description": "Creates or updates a user or workspace quota override with an admin reason.", + "security": [ + { + "BearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetAdminQuotaOverrideBody" + } + } + } + }, + "responses": { + "200": { + "description": "Admin quota override", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminQuotaOverride" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "422": { + "description": "Unprocessable entity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + }, + "/v1/admin/quota_overrides/{id}": { + "delete": { + "x-platform-visibility": "ADMIN", + "operationId": "adminAccess.removeQuotaOverride", + "tags": [ + "Admin Access" + ], + "summary": "Remove an admin quota override", + "description": "Revokes an active user or workspace quota override and keeps its audit history.", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 54 + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Removed admin quota override", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminQuotaOverride" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiErrorResponse" + } + } + } + } + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fc5e575 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "@akua-dev/cli", + "version": "0.0.0", + "private": false, + "type": "module", + "description": "Akua Cloud CLI", + "bin": { + "akua": "./src/bin/akua.ts" + }, + "scripts": { + "dev": "bun src/bin/akua.ts", + "build": "tsc --noEmit && bun build src/bin/akua.ts --target=bun --outdir=dist/js", + "build:binary": "bun build src/bin/akua.ts --compile --target=bun --outfile dist/akua", + "spec:fetch": "bun scripts/fetch-openapi.ts", + "generate": "bun scripts/generate-commands.ts", + "generate:check": "bun scripts/generate-commands.ts --check", + "test": "bun test" + }, + "devDependencies": { + "@types/bun": "^1.3.0", + "typescript": "^5.9.0" + }, + "engines": { + "bun": ">=1.3.7" + } +} diff --git a/scripts/fetch-openapi.ts b/scripts/fetch-openapi.ts new file mode 100644 index 0000000..c744cef --- /dev/null +++ b/scripts/fetch-openapi.ts @@ -0,0 +1,51 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; + +export const DEFAULT_OPENAPI_URL = "https://api.akua.dev/v1/openapi.json"; +export const DEFAULT_OUTPUT_PATH = "openapi/public.json"; + +export function resolveSpecUrl(input: string | undefined): URL { + const raw = input ?? process.env.AKUA_OPENAPI_URL ?? DEFAULT_OPENAPI_URL; + const url = new URL(raw); + if (url.protocol !== "https:") { + throw new Error(`OpenAPI URL must use https: ${url.href}`); + } + return url; +} + +export async function fetchOpenApi(url: URL, outputPath = DEFAULT_OUTPUT_PATH): Promise { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`OpenAPI fetch failed with ${response.status} ${response.statusText}`); + } + + const spec = await response.json(); + validateOpenApiDocument(spec); + + await mkdir(dirname(outputPath), { recursive: true }); + await writeFile(outputPath, `${JSON.stringify(spec, null, 2)}\n`); +} + +export function validateOpenApiDocument(value: unknown): asserts value is Record { + if (!value || typeof value !== "object") { + throw new Error("OpenAPI response is not an object"); + } + const spec = value as Record; + if (typeof spec.openapi !== "string" || !spec.openapi.startsWith("3.")) { + throw new Error("OpenAPI response must be OpenAPI 3.x"); + } + if (!spec.paths || typeof spec.paths !== "object") { + throw new Error("OpenAPI response is missing paths"); + } +} + +if (import.meta.main) { + try { + const url = resolveSpecUrl(process.argv[2]); + await fetchOpenApi(url); + console.error(`Fetched OpenAPI spec from ${url.href} into ${DEFAULT_OUTPUT_PATH}`); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); + } +} diff --git a/scripts/generate-commands.ts b/scripts/generate-commands.ts new file mode 100644 index 0000000..c056bbd --- /dev/null +++ b/scripts/generate-commands.ts @@ -0,0 +1,117 @@ +import { readFile, writeFile } from "node:fs/promises"; + +import type { CommandDefinition } from "../src/runtime/registry"; + +const SPEC_PATH = "openapi/public.json"; +const OUTPUT_PATH = "src/generated/commands.gen.ts"; +const HTTP_METHODS = new Set(["get", "post", "put", "patch", "delete"]); + +interface OpenApiOperation { + operationId?: string; + tags?: string[]; + summary?: string; + security?: unknown[]; + parameters?: OpenApiParameter[]; + "x-platform-visibility"?: string; +} + +interface OpenApiParameter { + name?: string; + in?: "path" | "query" | "header" | "cookie"; + required?: boolean; +} + +export async function generateCommandRegistry(specPath = SPEC_PATH): Promise { + const spec = JSON.parse(await readFile(specPath, "utf8")); + const commands = collectPublicCommands(spec); + return renderCommandRegistry(commands); +} + +export function collectPublicCommands(spec: unknown): CommandDefinition[] { + if (!spec || typeof spec !== "object") { + throw new Error("OpenAPI spec must be an object"); + } + + const paths = (spec as { paths?: unknown }).paths; + if (!paths || typeof paths !== "object") { + throw new Error("OpenAPI spec is missing paths"); + } + + const commands: CommandDefinition[] = []; + for (const [path, methods] of Object.entries(paths as Record)) { + if (!methods || typeof methods !== "object") { + continue; + } + for (const [method, rawOperation] of Object.entries(methods as Record)) { + if (!HTTP_METHODS.has(method) || !rawOperation || typeof rawOperation !== "object") { + continue; + } + const operation = rawOperation as OpenApiOperation; + if (operation["x-platform-visibility"] !== "PUBLIC") { + continue; + } + if (!operation.operationId) { + throw new Error(`Public operation at ${method.toUpperCase()} ${path} is missing operationId`); + } + commands.push(toCommandDefinition(method, path, operation)); + } + } + + return commands.sort((left, right) => left.operation_id.localeCompare(right.operation_id)); +} + +function toCommandDefinition(method: string, path: string, operation: OpenApiOperation): CommandDefinition { + const [resource, rawAction = method] = operation.operationId!.split("."); + const action = kebab(rawAction); + return { + operation_id: operation.operationId!, + command: `${kebab(resource)} ${action}`, + resource: kebab(resource), + action, + method: method.toUpperCase(), + path, + tag: operation.tags?.[0] ?? kebab(resource), + summary: operation.summary ?? operation.operationId!, + visibility: "PUBLIC", + requires_auth: Array.isArray(operation.security) && operation.security.length > 0, + parameters: (operation.parameters ?? []) + .filter((parameter) => parameter.name && parameter.in) + .map((parameter) => ({ + name: parameter.name!, + in: parameter.in!, + required: parameter.required === true, + })), + }; +} + +function renderCommandRegistry(commands: readonly CommandDefinition[]): string { + return `// Generated by scripts/generate-commands.ts. Do not edit by hand.\n` + + `import type { CommandDefinition } from "../runtime/registry";\n\n` + + `export const commandRegistry = ${JSON.stringify(commands, null, 2)} as const satisfies readonly CommandDefinition[];\n`; +} + +function kebab(value: string): string { + return value + .replace(/([a-z0-9])([A-Z])/g, "$1-$2") + .replace(/[_\s.]+/g, "-") + .toLowerCase(); +} + +if (import.meta.main) { + try { + const generated = await generateCommandRegistry(); + if (process.argv.includes("--check")) { + const current = await readFile(OUTPUT_PATH, "utf8").catch(() => ""); + if (current !== generated) { + console.error(`${OUTPUT_PATH} is out of date. Run: mise run generate`); + process.exit(1); + } + } else { + await writeFile(OUTPUT_PATH, generated); + console.error(`Generated ${OUTPUT_PATH}`); + } + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); + } +} diff --git a/src/bin/akua.ts b/src/bin/akua.ts new file mode 100644 index 0000000..13d5170 --- /dev/null +++ b/src/bin/akua.ts @@ -0,0 +1,203 @@ +#!/usr/bin/env bun +import { buildHomeView } from "../commands/home"; +import { commandRegistry } from "../generated/commands.gen"; +import { AkuaCliError, commandNotImplemented, usageError } from "../runtime/errors"; +import { detectOutputMode, type OutputMode } from "../runtime/mode"; +import { renderError, renderSuccess, type RenderEnvelope } from "../runtime/render"; + +const VERSION = "0.0.0"; + +export async function main(argv = process.argv.slice(2), env = process.env): Promise { + let mode: OutputMode = fallbackErrorMode(argv); + try { + mode = detectOutputMode({ argv, env, stdoutIsTTY: process.stdout.isTTY }); + const command = route(stripGlobalFlags(argv)); + process.stdout.write(renderSuccess(command, mode)); + return 0; + } catch (error) { + const cliError = error instanceof AkuaCliError ? error : usageError(error instanceof Error ? error.message : String(error)); + process.stdout.write(renderError(cliError, mode)); + return cliError.exitCode; + } +} + +function route(argv: readonly string[]): RenderEnvelope { + if (argv.length === 0) { + return buildHomeView(); + } + + if (argv.includes("--help") || argv.includes("-h")) { + return helpView(); + } + + if (argv.includes("--version") || argv.includes("-v") || argv.includes("-V")) { + return { + command: "akua --version", + observations: [VERSION], + data: { version: VERSION }, + }; + } + + if (argv[0] === "commands") { + return commandsView(argv.slice(1)); + } + + const unknownFlag = argv.find((arg) => arg.startsWith("-")); + if (unknownFlag) { + throw usageError(`Unknown flag: ${flagName(unknownFlag)}`); + } + + const maybeGenerated = commandRegistry.find((definition) => definition.command === argv.join(" ")); + if (maybeGenerated) { + throw commandNotImplemented(maybeGenerated.operation_id); + } + + throw usageError(`Unknown command: ${argv.join(" ")}`); +} + +function commandsView(argv: readonly string[]): RenderEnvelope { + const { operationId, resource, limit } = parseCommandsFlags(argv); + const filtered = commandRegistry + .filter((command) => !operationId || command.operation_id === operationId) + .filter((command) => !resource || command.resource === resource) + .slice(0, Number.isFinite(limit) && limit > 0 ? limit : 20) + .map((command) => ({ + operation_id: command.operation_id, + command: command.command, + method: command.method, + path: command.path, + summary: command.summary, + })); + + return { + command: "akua commands", + observations: [`${filtered.length} of ${commandRegistry.length} public operations shown.`], + data: filtered, + next_steps: [ + { command: "akua commands --resource workspaces" }, + { command: "akua commands --operation-id " }, + ], + }; +} + +function helpView(): RenderEnvelope { + return { + command: "akua --help", + observations: [ + "Usage: akua [--output human|agent|json|quiet] ", + "Commands:", + " akua Show compact home view", + " akua commands List generated public OpenAPI command registry", + " akua --help Show help", + " akua --version Show version", + ], + next_steps: [ + { command: "akua commands" }, + { command: "akua commands --json" }, + ], + }; +} + +function stripGlobalFlags(argv: readonly string[]): string[] { + const stripped: string[] = []; + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (value === "--json" || value === "--quiet" || value === "-q") { + continue; + } + if (value === "--output" || value === "-o") { + index += 1; + continue; + } + if (value.startsWith("--output=") || value.startsWith("-o=")) { + continue; + } + stripped.push(value); + } + return stripped; +} + +interface CommandsFilters { + operationId?: string; + resource?: string; + limit: number; +} + +function parseCommandsFlags(argv: readonly string[]): CommandsFilters { + const knownFlags = new Set(["--operation-id", "--resource", "--limit"]); + let operationId: string | undefined; + let resource: string | undefined; + let limit = 20; + + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (!value.startsWith("-")) { + throw usageError(`Unexpected argument for commands: ${value}`); + } + + const name = flagName(value); + if (!knownFlags.has(name)) { + throw usageError(`Unknown flag: ${name}`); + } + + const raw = readFlagValue(argv, index, name); + if (raw.value === undefined || raw.value === "") { + throw usageError(`Missing value for ${name}.`); + } + if (raw.consumedNext) { + index += 1; + } + + if (name === "--operation-id") { + operationId = raw.value; + } else if (name === "--resource") { + resource = raw.value; + } else { + limit = parsePositiveInteger(raw.value, name); + } + } + + return { operationId, resource, limit }; +} + +function readFlagValue( + argv: readonly string[], + index: number, + flag: string, +): { value: string | undefined; consumedNext: boolean } { + const value = argv[index]; + if (value === flag) { + const next = argv[index + 1]; + if (next === undefined || (next.startsWith("-") && !(flag === "--limit" && /^-\d/.test(next)))) { + return { value: undefined, consumedNext: false }; + } + return { value: next, consumedNext: true }; + } + + return { value: value.slice(flag.length + 1), consumedNext: false }; +} + +function flagName(value: string): string { + return value.includes("=") ? value.slice(0, value.indexOf("=")) : value; +} + +function parsePositiveInteger(value: string, flag: string): number { + if (!/^[1-9]\d*$/.test(value)) { + throw usageError(`Invalid value for ${flag}: ${value}. Expected a positive integer.`); + } + return Number(value); +} + +function fallbackErrorMode(argv: readonly string[]): OutputMode { + if (argv.includes("--json")) { + return "json"; + } + if (argv.includes("--quiet") || argv.includes("-q")) { + return "quiet"; + } + return "human"; +} + +if (import.meta.main) { + process.exit(await main()); +} diff --git a/src/commands/home.ts b/src/commands/home.ts new file mode 100644 index 0000000..69d5684 --- /dev/null +++ b/src/commands/home.ts @@ -0,0 +1,29 @@ +import { commandRegistry } from "../generated/commands.gen"; +import type { RenderEnvelope } from "../runtime/render"; + +export function buildHomeView(): RenderEnvelope { + const byTag = new Map(); + for (const command of commandRegistry) { + byTag.set(command.tag, (byTag.get(command.tag) ?? 0) + 1); + } + + const topTags = [...byTag.entries()] + .sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])) + .slice(0, 6) + .map(([tag, count]) => ({ tag, operations: count })); + + return { + command: "akua", + observations: [ + "Akua Cloud CLI scaffold.", + `${commandRegistry.length} public OpenAPI operations are registered for generated commands.`, + "API execution is intentionally stubbed in this prototype.", + ], + data: topTags, + next_steps: [ + { command: "akua commands" }, + { command: "akua commands --json" }, + { command: "mise run spec:fetch && mise run generate" }, + ], + }; +} diff --git a/src/generated/commands.gen.ts b/src/generated/commands.gen.ts new file mode 100644 index 0000000..f2a8849 --- /dev/null +++ b/src/generated/commands.gen.ts @@ -0,0 +1,6228 @@ +// Generated by scripts/generate-commands.ts. Do not edit by hand. +import type { CommandDefinition } from "../runtime/registry"; + +export const commandRegistry = [ + { + "operation_id": "accessDecisions.explain", + "command": "access-decisions explain", + "resource": "access-decisions", + "action": "explain", + "method": "POST", + "path": "/v1/access_decisions", + "tag": "Access Decisions", + "summary": "Explain an access decision", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "agentEvents.list", + "command": "agent-events list", + "resource": "agent-events", + "action": "list", + "method": "GET", + "path": "/v1/agent_events", + "tag": "Agent events", + "summary": "List agent events", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "session", + "in": "query", + "required": false + }, + { + "name": "turn", + "in": "query", + "required": false + }, + { + "name": "parent_session", + "in": "query", + "required": false + }, + { + "name": "forked_from_session", + "in": "query", + "required": false + }, + { + "name": "spawned_by_turn", + "in": "query", + "required": false + }, + { + "name": "agent_role", + "in": "query", + "required": false + }, + { + "name": "follow", + "in": "query", + "required": false + }, + { + "name": "after", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentEvents.stream", + "command": "agent-events stream", + "resource": "agent-events", + "action": "stream", + "method": "GET", + "path": "/v1/agent_events:stream", + "tag": "Agent events", + "summary": "Stream agent events", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "session", + "in": "query", + "required": false + }, + { + "name": "turn", + "in": "query", + "required": false + }, + { + "name": "parent_session", + "in": "query", + "required": false + }, + { + "name": "forked_from_session", + "in": "query", + "required": false + }, + { + "name": "spawned_by_turn", + "in": "query", + "required": false + }, + { + "name": "agent_role", + "in": "query", + "required": false + }, + { + "name": "follow", + "in": "query", + "required": false + }, + { + "name": "after", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentPreferences.get", + "command": "agent-preferences get", + "resource": "agent-preferences", + "action": "get", + "method": "GET", + "path": "/v1/agent_preferences", + "tag": "Agent preferences", + "summary": "Get agent preferences", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentPreferences.update", + "command": "agent-preferences update", + "resource": "agent-preferences", + "action": "update", + "method": "PATCH", + "path": "/v1/agent_preferences", + "tag": "Agent preferences", + "summary": "Update agent preferences", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentProviderExchanges.list", + "command": "agent-provider-exchanges list", + "resource": "agent-provider-exchanges", + "action": "list", + "method": "GET", + "path": "/v1/agent_provider_exchanges", + "tag": "Agent provider exchanges", + "summary": "List agent provider exchanges", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "turn", + "in": "query", + "required": true + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agents.archive", + "command": "agents archive", + "resource": "agents", + "action": "archive", + "method": "DELETE", + "path": "/v1/agents/{id}", + "tag": "Agents", + "summary": "Archive agent", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agents.create", + "command": "agents create", + "resource": "agents", + "action": "create", + "method": "POST", + "path": "/v1/agents", + "tag": "Agents", + "summary": "Create agent", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agents.enable", + "command": "agents enable", + "resource": "agents", + "action": "enable", + "method": "POST", + "path": "/v1/agents/{id}:enable", + "tag": "Agents", + "summary": "Enable agent", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agents.get", + "command": "agents get", + "resource": "agents", + "action": "get", + "method": "GET", + "path": "/v1/agents/{id}", + "tag": "Agents", + "summary": "Get agent", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agents.list", + "command": "agents list", + "resource": "agents", + "action": "list", + "method": "GET", + "path": "/v1/agents", + "tag": "Agents", + "summary": "List agents", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agents.update", + "command": "agents update", + "resource": "agents", + "action": "update", + "method": "PATCH", + "path": "/v1/agents/{id}", + "tag": "Agents", + "summary": "Update agent", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "agentSessions.archive", + "command": "agent-sessions archive", + "resource": "agent-sessions", + "action": "archive", + "method": "DELETE", + "path": "/v1/agent_sessions/{id}", + "tag": "Agent sessions", + "summary": "Archive agent session", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agentSessions.create", + "command": "agent-sessions create", + "resource": "agent-sessions", + "action": "create", + "method": "POST", + "path": "/v1/agent_sessions", + "tag": "Agent sessions", + "summary": "Create agent session", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentSessions.detectConflicts", + "command": "agent-sessions detect-conflicts", + "resource": "agent-sessions", + "action": "detect-conflicts", + "method": "GET", + "path": "/v1/agent_sessions:detectConflicts", + "tag": "Agent sessions", + "summary": "Detect agent work conflicts", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "resource", + "in": "query", + "required": true + }, + { + "name": "id", + "in": "query", + "required": true + }, + { + "name": "exclude_session", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentSessions.get", + "command": "agent-sessions get", + "resource": "agent-sessions", + "action": "get", + "method": "GET", + "path": "/v1/agent_sessions/{id}", + "tag": "Agent sessions", + "summary": "Get agent session", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agentSessions.list", + "command": "agent-sessions list", + "resource": "agent-sessions", + "action": "list", + "method": "GET", + "path": "/v1/agent_sessions", + "tag": "Agent sessions", + "summary": "List agent sessions", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "parent_session", + "in": "query", + "required": false + }, + { + "name": "forked_from_session", + "in": "query", + "required": false + }, + { + "name": "spawned_by_turn", + "in": "query", + "required": false + }, + { + "name": "agent_role", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentSessions.setRetention", + "command": "agent-sessions set-retention", + "resource": "agent-sessions", + "action": "set-retention", + "method": "POST", + "path": "/v1/agent_sessions/{id}:setRetention", + "tag": "Agent sessions", + "summary": "Set agent session retention", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agentSkills.get", + "command": "agent-skills get", + "resource": "agent-skills", + "action": "get", + "method": "GET", + "path": "/v1/agent_skills/{id}", + "tag": "Agent skills", + "summary": "Get agent skill", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agentSkills.list", + "command": "agent-skills list", + "resource": "agent-skills", + "action": "list", + "method": "GET", + "path": "/v1/agent_skills", + "tag": "Agent skills", + "summary": "List agent skills", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentTemplates.get", + "command": "agent-templates get", + "resource": "agent-templates", + "action": "get", + "method": "GET", + "path": "/v1/agent_templates/{id}", + "tag": "Agent templates", + "summary": "Get agent template", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agentTemplates.list", + "command": "agent-templates list", + "resource": "agent-templates", + "action": "list", + "method": "GET", + "path": "/v1/agent_templates", + "tag": "Agent templates", + "summary": "List agent templates", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentTurns.cancel", + "command": "agent-turns cancel", + "resource": "agent-turns", + "action": "cancel", + "method": "POST", + "path": "/v1/agent_turns/{id}:cancel", + "tag": "Agent turns", + "summary": "Cancel agent turn", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentTurns.create", + "command": "agent-turns create", + "resource": "agent-turns", + "action": "create", + "method": "POST", + "path": "/v1/agent_turns", + "tag": "Agent turns", + "summary": "Submit agent turn", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "agentTurns.emit", + "command": "agent-turns emit", + "resource": "agent-turns", + "action": "emit", + "method": "POST", + "path": "/v1/agent_turns/{id}:emit", + "tag": "Agent turns", + "summary": "Emit agent turn event", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "agentTurns.get", + "command": "agent-turns get", + "resource": "agent-turns", + "action": "get", + "method": "GET", + "path": "/v1/agent_turns/{id}", + "tag": "Agent turns", + "summary": "Get agent turn", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "agentTurns.list", + "command": "agent-turns list", + "resource": "agent-turns", + "action": "list", + "method": "GET", + "path": "/v1/agent_turns", + "tag": "Agent turns", + "summary": "List agent turns", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "session", + "in": "query", + "required": false + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "apiTokens.create", + "command": "api-tokens create", + "resource": "api-tokens", + "action": "create", + "method": "POST", + "path": "/v1/api_tokens", + "tag": "API Tokens", + "summary": "Create an API token", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "apiTokens.list", + "command": "api-tokens list", + "resource": "api-tokens", + "action": "list", + "method": "GET", + "path": "/v1/api_tokens", + "tag": "API Tokens", + "summary": "List API tokens", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "apiTokens.revoke", + "command": "api-tokens revoke", + "resource": "api-tokens", + "action": "revoke", + "method": "DELETE", + "path": "/v1/api_tokens/{id}", + "tag": "API Tokens", + "summary": "Revoke an API token", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "approvalRequests.list", + "command": "approval-requests list", + "resource": "approval-requests", + "action": "list", + "method": "GET", + "path": "/v1/approval_requests", + "tag": "Approval requests", + "summary": "List approval requests", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "agent", + "in": "query", + "required": false + }, + { + "name": "session", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "approvalRequests.resolve", + "command": "approval-requests resolve", + "resource": "approval-requests", + "action": "resolve", + "method": "POST", + "path": "/v1/approval_requests/{id}:resolve", + "tag": "Approval requests", + "summary": "Resolve approval request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "cloudflare.createCredential", + "command": "cloudflare create-credential", + "resource": "cloudflare", + "action": "create-credential", + "method": "POST", + "path": "/v1/cloudflare_connections", + "tag": "Cloudflare", + "summary": "Create Cloudflare credential", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "cloudflare.deleteCredential", + "command": "cloudflare delete-credential", + "resource": "cloudflare", + "action": "delete-credential", + "method": "DELETE", + "path": "/v1/cloudflare_connections/{id}", + "tag": "Cloudflare", + "summary": "Delete Cloudflare credential", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "cloudflare.listCredentials", + "command": "cloudflare list-credentials", + "resource": "cloudflare", + "action": "list-credentials", + "method": "GET", + "path": "/v1/cloudflare_connections", + "tag": "Cloudflare", + "summary": "List Cloudflare credentials", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.create", + "command": "clusters create", + "resource": "clusters", + "action": "create", + "method": "POST", + "path": "/v1/clusters", + "tag": "Clusters", + "summary": "Create cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.createWorkerBootstrap", + "command": "clusters create-worker-bootstrap", + "resource": "clusters", + "action": "create-worker-bootstrap", + "method": "POST", + "path": "/v1/clusters/{id}/worker_bootstraps", + "tag": "Clusters", + "summary": "Create worker bootstrap", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.delete", + "command": "clusters delete", + "resource": "clusters", + "action": "delete", + "method": "DELETE", + "path": "/v1/clusters/{id}", + "tag": "Clusters", + "summary": "Delete cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "clusters.exec", + "command": "clusters exec", + "resource": "clusters", + "action": "exec", + "method": "POST", + "path": "/v1/clusters/{id}:exec", + "tag": "Clusters", + "summary": "Execute command in cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "clusters.get", + "command": "clusters get", + "resource": "clusters", + "action": "get", + "method": "GET", + "path": "/v1/clusters/{id}", + "tag": "Clusters", + "summary": "Get cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.getCapabilities", + "command": "clusters get-capabilities", + "resource": "clusters", + "action": "get-capabilities", + "method": "GET", + "path": "/v1/clusters/{id}/capabilities", + "tag": "Clusters", + "summary": "Get cluster capabilities", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.getKubeconfig", + "command": "clusters get-kubeconfig", + "resource": "clusters", + "action": "get-kubeconfig", + "method": "GET", + "path": "/v1/clusters/{id}/kubeconfig", + "tag": "Clusters", + "summary": "Get cluster kubeconfig", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.getWorkerBootstrap", + "command": "clusters get-worker-bootstrap", + "resource": "clusters", + "action": "get-worker-bootstrap", + "method": "GET", + "path": "/v1/clusters/{id}/worker_bootstraps/{wbs_id}", + "tag": "Clusters", + "summary": "Get cluster worker bootstrap", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "wbs_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.import", + "command": "clusters import", + "resource": "clusters", + "action": "import", + "method": "POST", + "path": "/v1/clusters:import", + "tag": "Clusters", + "summary": "Import cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.list", + "command": "clusters list", + "resource": "clusters", + "action": "list", + "method": "GET", + "path": "/v1/clusters", + "tag": "Clusters", + "summary": "List clusters", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.listWorkerBootstraps", + "command": "clusters list-worker-bootstraps", + "resource": "clusters", + "action": "list-worker-bootstraps", + "method": "GET", + "path": "/v1/clusters/{id}/worker_bootstraps", + "tag": "Clusters", + "summary": "List cluster worker bootstraps", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.proxyKube", + "command": "clusters proxy-kube", + "resource": "clusters", + "action": "proxy-kube", + "method": "GET", + "path": "/v1/clusters/{id}/kube_proxy/{path:*}", + "tag": "Clusters", + "summary": "Proxy cluster API", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "path", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.refreshCapabilities", + "command": "clusters refresh-capabilities", + "resource": "clusters", + "action": "refresh-capabilities", + "method": "POST", + "path": "/v1/clusters/{id}/capabilities:refresh", + "tag": "Clusters", + "summary": "Refresh cluster capabilities", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "clusters.resume", + "command": "clusters resume", + "resource": "clusters", + "action": "resume", + "method": "POST", + "path": "/v1/clusters/{id}:resume", + "tag": "Clusters", + "summary": "Resume cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "clusters.revokeWorkerBootstrap", + "command": "clusters revoke-worker-bootstrap", + "resource": "clusters", + "action": "revoke-worker-bootstrap", + "method": "POST", + "path": "/v1/clusters/{id}/worker_bootstraps/{wbs_id}:revoke", + "tag": "Clusters", + "summary": "Revoke worker bootstrap", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "wbs_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "clusters.suspend", + "command": "clusters suspend", + "resource": "clusters", + "action": "suspend", + "method": "POST", + "path": "/v1/clusters/{id}:suspend", + "tag": "Clusters", + "summary": "Suspend cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "clusters.update", + "command": "clusters update", + "resource": "clusters", + "action": "update", + "method": "PATCH", + "path": "/v1/clusters/{id}", + "tag": "Clusters", + "summary": "Update cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "compute.checkMachineDrift", + "command": "compute check-machine-drift", + "resource": "compute", + "action": "check-machine-drift", + "method": "GET", + "path": "/v1/compute/machines/{providerId}/drift", + "tag": "Compute", + "summary": "Check if machine has drifted", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "providerId", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.createConfig", + "command": "compute create-config", + "resource": "compute", + "action": "create-config", + "method": "POST", + "path": "/v1/compute/configs", + "tag": "Compute", + "summary": "Create a compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "compute.createMachine", + "command": "compute create-machine", + "resource": "compute", + "action": "create-machine", + "method": "POST", + "path": "/v1/compute/machines", + "tag": "Compute", + "summary": "Create a machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "compute.deleteConfig", + "command": "compute delete-config", + "resource": "compute", + "action": "delete-config", + "method": "DELETE", + "path": "/v1/compute/configs/{id}", + "tag": "Compute", + "summary": "Delete a compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "compute.deleteMachine", + "command": "compute delete-machine", + "resource": "compute", + "action": "delete-machine", + "method": "DELETE", + "path": "/v1/compute/machines/{providerId}", + "tag": "Compute", + "summary": "Delete a machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "providerId", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.deleteSuspension", + "command": "compute delete-suspension", + "resource": "compute", + "action": "delete-suspension", + "method": "DELETE", + "path": "/v1/compute/suspensions/{id}", + "tag": "Compute", + "summary": "Delete a suspension", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.getClusterStatus", + "command": "compute get-cluster-status", + "resource": "compute", + "action": "get-cluster-status", + "method": "GET", + "path": "/v1/clusters/{clusterId}/compute_status", + "tag": "Compute", + "summary": "Get cluster compute status", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "clusterId", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.getConfig", + "command": "compute get-config", + "resource": "compute", + "action": "get-config", + "method": "GET", + "path": "/v1/compute/configs/{id}", + "tag": "Compute", + "summary": "Get a compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.getMachine", + "command": "compute get-machine", + "resource": "compute", + "action": "get-machine", + "method": "GET", + "path": "/v1/compute/machines/{providerId}", + "tag": "Compute", + "summary": "Get machine status", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "providerId", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.listConfigs", + "command": "compute list-configs", + "resource": "compute", + "action": "list-configs", + "method": "GET", + "path": "/v1/compute/configs", + "tag": "Compute", + "summary": "List compute configs", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "compute.listInstanceTypes", + "command": "compute list-instance-types", + "resource": "compute", + "action": "list-instance-types", + "method": "GET", + "path": "/v1/compute/instance_types", + "tag": "Compute", + "summary": "List available instance types", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "config", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "compute.listMachines", + "command": "compute list-machines", + "resource": "compute", + "action": "list-machines", + "method": "GET", + "path": "/v1/compute/machines", + "tag": "Compute", + "summary": "List machines in cluster", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cluster", + "in": "query", + "required": true + } + ] + }, + { + "operation_id": "compute.listSuspensions", + "command": "compute list-suspensions", + "resource": "compute", + "action": "list-suspensions", + "method": "GET", + "path": "/v1/compute/suspensions", + "tag": "Compute", + "summary": "List suspended machines", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "compute.resumeSuspension", + "command": "compute resume-suspension", + "resource": "compute", + "action": "resume-suspension", + "method": "POST", + "path": "/v1/compute/suspensions/{id}/resume", + "tag": "Compute", + "summary": "Resume a suspended machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.suspendMachine", + "command": "compute suspend-machine", + "resource": "compute", + "action": "suspend-machine", + "method": "POST", + "path": "/v1/compute/machines/{providerId}/suspend", + "tag": "Compute", + "summary": "Suspend a machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "providerId", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "compute.updateClusterSettings", + "command": "compute update-cluster-settings", + "resource": "compute", + "action": "update-cluster-settings", + "method": "PATCH", + "path": "/v1/clusters/{clusterId}/compute_settings", + "tag": "Compute", + "summary": "Update cluster compute settings", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "clusterId", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "computeConfigs.create", + "command": "compute-configs create", + "resource": "compute-configs", + "action": "create", + "method": "POST", + "path": "/v1/compute_configs", + "tag": "ComputeConfigs", + "summary": "Create compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "computeConfigs.delete", + "command": "compute-configs delete", + "resource": "compute-configs", + "action": "delete", + "method": "DELETE", + "path": "/v1/compute_configs/{id}", + "tag": "ComputeConfigs", + "summary": "Delete compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "computeConfigs.get", + "command": "compute-configs get", + "resource": "compute-configs", + "action": "get", + "method": "GET", + "path": "/v1/compute_configs/{id}", + "tag": "ComputeConfigs", + "summary": "Get compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "computeConfigs.list", + "command": "compute-configs list", + "resource": "compute-configs", + "action": "list", + "method": "GET", + "path": "/v1/compute_configs", + "tag": "ComputeConfigs", + "summary": "List compute configs", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "view", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "computeConfigs.update", + "command": "compute-configs update", + "resource": "compute-configs", + "action": "update", + "method": "PATCH", + "path": "/v1/compute_configs/{id}", + "tag": "ComputeConfigs", + "summary": "Update compute config", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "customDomains.create", + "command": "custom-domains create", + "resource": "custom-domains", + "action": "create", + "method": "POST", + "path": "/v1/workspaces/{id}/custom_domains", + "tag": "Custom domains", + "summary": "Create custom domain", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "customDomains.delete", + "command": "custom-domains delete", + "resource": "custom-domains", + "action": "delete", + "method": "DELETE", + "path": "/v1/workspaces/{id}/custom_domains/{custom_domain_id}", + "tag": "Custom domains", + "summary": "Delete custom domain", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "custom_domain_id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "customDomains.get", + "command": "custom-domains get", + "resource": "custom-domains", + "action": "get", + "method": "GET", + "path": "/v1/workspaces/{id}/custom_domains/{custom_domain_id}", + "tag": "Custom domains", + "summary": "Get custom domain", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "custom_domain_id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "customDomains.list", + "command": "custom-domains list", + "resource": "custom-domains", + "action": "list", + "method": "GET", + "path": "/v1/workspaces/{id}/custom_domains", + "tag": "Custom domains", + "summary": "List custom domains", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "target_kind", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "customDomains.update", + "command": "custom-domains update", + "resource": "custom-domains", + "action": "update", + "method": "PATCH", + "path": "/v1/workspaces/{id}/custom_domains/{custom_domain_id}", + "tag": "Custom domains", + "summary": "Update custom domain", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "custom_domain_id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "dashboards.create", + "command": "dashboards create", + "resource": "dashboards", + "action": "create", + "method": "POST", + "path": "/v1/dashboards", + "tag": "Dashboards", + "summary": "Create dashboard", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "dashboards.createWidget", + "command": "dashboards create-widget", + "resource": "dashboards", + "action": "create-widget", + "method": "POST", + "path": "/v1/dashboards/{id}/widgets", + "tag": "Dashboards", + "summary": "Create dashboard widget", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "dashboards.delete", + "command": "dashboards delete", + "resource": "dashboards", + "action": "delete", + "method": "DELETE", + "path": "/v1/dashboards/{id}", + "tag": "Dashboards", + "summary": "Delete dashboard", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "dashboards.deleteWidget", + "command": "dashboards delete-widget", + "resource": "dashboards", + "action": "delete-widget", + "method": "DELETE", + "path": "/v1/dashboards/{id}/widgets/{wgt_id}", + "tag": "Dashboards", + "summary": "Delete dashboard widget", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "wgt_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "dashboards.get", + "command": "dashboards get", + "resource": "dashboards", + "action": "get", + "method": "GET", + "path": "/v1/dashboards/{id}", + "tag": "Dashboards", + "summary": "Get dashboard details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "dashboards.getWidget", + "command": "dashboards get-widget", + "resource": "dashboards", + "action": "get-widget", + "method": "GET", + "path": "/v1/dashboards/{id}/widgets/{wgt_id}", + "tag": "Dashboards", + "summary": "Get dashboard widget", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "wgt_id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "dashboards.list", + "command": "dashboards list", + "resource": "dashboards", + "action": "list", + "method": "GET", + "path": "/v1/dashboards", + "tag": "Dashboards", + "summary": "List dashboards in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "dashboards.listWidgets", + "command": "dashboards list-widgets", + "resource": "dashboards", + "action": "list-widgets", + "method": "GET", + "path": "/v1/dashboards/{id}/widgets", + "tag": "Dashboards", + "summary": "List dashboard widgets", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "dashboards.update", + "command": "dashboards update", + "resource": "dashboards", + "action": "update", + "method": "PATCH", + "path": "/v1/dashboards/{id}", + "tag": "Dashboards", + "summary": "Update dashboard", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "dashboards.updateWidget", + "command": "dashboards update-widget", + "resource": "dashboards", + "action": "update-widget", + "method": "PATCH", + "path": "/v1/dashboards/{id}/widgets/{wgt_id}", + "tag": "Dashboards", + "summary": "Update dashboard widget", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "wgt_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "entitlements.list", + "command": "entitlements list", + "resource": "entitlements", + "action": "list", + "method": "GET", + "path": "/v1/entitlements", + "tag": "Entitlements", + "summary": "List entitlements", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "workspace", + "in": "query", + "required": false + }, + { + "name": "feature_set", + "in": "query", + "required": false + }, + { + "name": "feature", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "installs.create", + "command": "installs create", + "resource": "installs", + "action": "create", + "method": "POST", + "path": "/v1/installs", + "tag": "Installs", + "summary": "Create install", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.createRender", + "command": "installs create-render", + "resource": "installs", + "action": "create-render", + "method": "POST", + "path": "/v1/installs/{id}/renders", + "tag": "Installs", + "summary": "Create install render", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.delete", + "command": "installs delete", + "resource": "installs", + "action": "delete", + "method": "DELETE", + "path": "/v1/installs/{id}", + "tag": "Installs", + "summary": "Delete install", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "installs.get", + "command": "installs get", + "resource": "installs", + "action": "get", + "method": "GET", + "path": "/v1/installs/{id}", + "tag": "Installs", + "summary": "Get install details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.getLogs", + "command": "installs get-logs", + "resource": "installs", + "action": "get-logs", + "method": "GET", + "path": "/v1/installs/{id}/logs", + "tag": "Installs", + "summary": "Stream install logs", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "pod", + "in": "query", + "required": false + }, + { + "name": "container", + "in": "query", + "required": false + }, + { + "name": "follow", + "in": "query", + "required": false + }, + { + "name": "tail", + "in": "query", + "required": false + }, + { + "name": "since_seconds", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.getRender", + "command": "installs get-render", + "resource": "installs", + "action": "get-render", + "method": "GET", + "path": "/v1/installs/{id}/renders/{render_id}", + "tag": "Installs", + "summary": "Get install render", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "render_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.getStatus", + "command": "installs get-status", + "resource": "installs", + "action": "get-status", + "method": "GET", + "path": "/v1/installs/{id}/status", + "tag": "Installs", + "summary": "Get install status", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.list", + "command": "installs list", + "resource": "installs", + "action": "list", + "method": "GET", + "path": "/v1/installs", + "tag": "Installs", + "summary": "List installs", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "product_id", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.listPods", + "command": "installs list-pods", + "resource": "installs", + "action": "list-pods", + "method": "GET", + "path": "/v1/installs/{id}/pods", + "tag": "Installs", + "summary": "List install pods", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "installs.listRenders", + "command": "installs list-renders", + "resource": "installs", + "action": "list-renders", + "method": "GET", + "path": "/v1/installs/{id}/renders", + "tag": "Installs", + "summary": "List install renders", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.create", + "command": "machines create", + "resource": "machines", + "action": "create", + "method": "POST", + "path": "/v1/machines", + "tag": "Machines", + "summary": "Create machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.createDriftReport", + "command": "machines create-drift-report", + "resource": "machines", + "action": "create-drift-report", + "method": "POST", + "path": "/v1/machines/{id}/drift_reports", + "tag": "Machines", + "summary": "Create machine drift report", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.delete", + "command": "machines delete", + "resource": "machines", + "action": "delete", + "method": "DELETE", + "path": "/v1/machines/{id}", + "tag": "Machines", + "summary": "Delete machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "machines.get", + "command": "machines get", + "resource": "machines", + "action": "get", + "method": "GET", + "path": "/v1/machines/{id}", + "tag": "Machines", + "summary": "Get machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.getDriftReport", + "command": "machines get-drift-report", + "resource": "machines", + "action": "get-drift-report", + "method": "GET", + "path": "/v1/machines/{id}/drift_reports/{report_id}", + "tag": "Machines", + "summary": "Get machine drift report", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "report_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.getSuspensionEvent", + "command": "machines get-suspension-event", + "resource": "machines", + "action": "get-suspension-event", + "method": "GET", + "path": "/v1/machines/{id}/suspension_events/{event_id}", + "tag": "Machines", + "summary": "Get machine suspension event", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "event_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.list", + "command": "machines list", + "resource": "machines", + "action": "list", + "method": "GET", + "path": "/v1/machines", + "tag": "Machines", + "summary": "List machines", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "cluster_id", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "view", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.listDriftReports", + "command": "machines list-drift-reports", + "resource": "machines", + "action": "list-drift-reports", + "method": "GET", + "path": "/v1/machines/{id}/drift_reports", + "tag": "Machines", + "summary": "List machine drift reports", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.listSuspensionEvents", + "command": "machines list-suspension-events", + "resource": "machines", + "action": "list-suspension-events", + "method": "GET", + "path": "/v1/machines/{id}/suspension_events", + "tag": "Machines", + "summary": "List machine suspension events", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "reason", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "machines.resume", + "command": "machines resume", + "resource": "machines", + "action": "resume", + "method": "POST", + "path": "/v1/machines/{id}:resume", + "tag": "Machines", + "summary": "Resume machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "machines.suspend", + "command": "machines suspend", + "resource": "machines", + "action": "suspend", + "method": "POST", + "path": "/v1/machines/{id}:suspend", + "tag": "Machines", + "summary": "Suspend machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "machines.update", + "command": "machines update", + "resource": "machines", + "action": "update", + "method": "PATCH", + "path": "/v1/machines/{id}", + "tag": "Machines", + "summary": "Update machine", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "notifications.getUnreadCount", + "command": "notifications get-unread-count", + "resource": "notifications", + "action": "get-unread-count", + "method": "GET", + "path": "/v1/notifications/unread_count", + "tag": "Notifications", + "summary": "Count unread notifications", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "notifications.list", + "command": "notifications list", + "resource": "notifications", + "action": "list", + "method": "GET", + "path": "/v1/notifications", + "tag": "Notifications", + "summary": "List recent notifications", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "unread", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "notifications.markAllRead", + "command": "notifications mark-all-read", + "resource": "notifications", + "action": "mark-all-read", + "method": "POST", + "path": "/v1/notifications/mark_all_read", + "tag": "Notifications", + "summary": "Mark all notifications as read", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "notifications.markRead", + "command": "notifications mark-read", + "resource": "notifications", + "action": "mark-read", + "method": "PATCH", + "path": "/v1/notifications/{id}/read", + "tag": "Notifications", + "summary": "Mark a notification as read", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "offers.archive", + "command": "offers archive", + "resource": "offers", + "action": "archive", + "method": "POST", + "path": "/v1/offers/{id}:archive", + "tag": "Offers", + "summary": "Archive offer", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "offers.create", + "command": "offers create", + "resource": "offers", + "action": "create", + "method": "POST", + "path": "/v1/offers", + "tag": "Offers", + "summary": "Create offer", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "offers.get", + "command": "offers get", + "resource": "offers", + "action": "get", + "method": "GET", + "path": "/v1/offers/{id}", + "tag": "Offers", + "summary": "Get offer details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "offers.list", + "command": "offers list", + "resource": "offers", + "action": "list", + "method": "GET", + "path": "/v1/offers", + "tag": "Offers", + "summary": "List offers in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "product_id", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "offers.resolve", + "command": "offers resolve", + "resource": "offers", + "action": "resolve", + "method": "GET", + "path": "/v1/offers:resolve", + "tag": "Offers", + "summary": "Resolve offer by short hash", + "visibility": "PUBLIC", + "requires_auth": false, + "parameters": [ + { + "name": "short_hash", + "in": "query", + "required": true + } + ] + }, + { + "operation_id": "offers.unarchive", + "command": "offers unarchive", + "resource": "offers", + "action": "unarchive", + "method": "POST", + "path": "/v1/offers/{id}:unarchive", + "tag": "Offers", + "summary": "Unarchive offer", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "operations.cancel", + "command": "operations cancel", + "resource": "operations", + "action": "cancel", + "method": "POST", + "path": "/v1/operations/{id}:cancel", + "tag": "Operations", + "summary": "Request operation cancellation", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "operations.get", + "command": "operations get", + "resource": "operations", + "action": "get", + "method": "GET", + "path": "/v1/operations/{id}", + "tag": "Operations", + "summary": "Get operation details + steps", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "operations.list", + "command": "operations list", + "resource": "operations", + "action": "list", + "method": "GET", + "path": "/v1/operations", + "tag": "Operations", + "summary": "List operations", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "owner_type", + "in": "query", + "required": false + }, + { + "name": "owner_id", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "operations.wait", + "command": "operations wait", + "resource": "operations", + "action": "wait", + "method": "POST", + "path": "/v1/operations/{id}:wait", + "tag": "Operations", + "summary": "Wait for an operation to reach a terminal state", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "timeout", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "orderDrafts.cancel", + "command": "order-drafts cancel", + "resource": "order-drafts", + "action": "cancel", + "method": "POST", + "path": "/v1/order_drafts/{id}:cancel", + "tag": "Order Drafts", + "summary": "Cancel order draft", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.claim", + "command": "order-drafts claim", + "resource": "order-drafts", + "action": "claim", + "method": "POST", + "path": "/v1/order_drafts/{id}:claim", + "tag": "Order Drafts", + "summary": "Claim order draft", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.create", + "command": "order-drafts create", + "resource": "order-drafts", + "action": "create", + "method": "POST", + "path": "/v1/offers/{offer}/order_drafts", + "tag": "Order Drafts", + "summary": "Create order draft", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "offer", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "orderDrafts.createCheckoutSession", + "command": "order-drafts create-checkout-session", + "resource": "order-drafts", + "action": "create-checkout-session", + "method": "POST", + "path": "/v1/order_drafts/{id}/checkout_sessions", + "tag": "Order Drafts", + "summary": "Create order draft checkout session", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.createWorkerBootstrap", + "command": "order-drafts create-worker-bootstrap", + "resource": "order-drafts", + "action": "create-worker-bootstrap", + "method": "POST", + "path": "/v1/order_drafts/{id}:createWorkerBootstrap", + "tag": "Order Drafts", + "summary": "Create order draft worker bootstrap", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.get", + "command": "order-drafts get", + "resource": "order-drafts", + "action": "get", + "method": "GET", + "path": "/v1/order_drafts/{id}", + "tag": "Order Drafts", + "summary": "Get order draft details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.getCheckoutSession", + "command": "order-drafts get-checkout-session", + "resource": "order-drafts", + "action": "get-checkout-session", + "method": "GET", + "path": "/v1/order_drafts/{id}/checkout_sessions/{chk_id}", + "tag": "Order Drafts", + "summary": "Get order draft checkout session", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "chk_id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.list", + "command": "order-drafts list", + "resource": "order-drafts", + "action": "list", + "method": "GET", + "path": "/v1/order_drafts", + "tag": "Order Drafts", + "summary": "List order drafts", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "offer", + "in": "query", + "required": false + }, + { + "name": "status", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "orderDrafts.listCheckoutSessions", + "command": "order-drafts list-checkout-sessions", + "resource": "order-drafts", + "action": "list-checkout-sessions", + "method": "GET", + "path": "/v1/order_drafts/{id}/checkout_sessions", + "tag": "Order Drafts", + "summary": "List order draft checkout sessions", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "orderDrafts.selectWorkspace", + "command": "order-drafts select-workspace", + "resource": "order-drafts", + "action": "select-workspace", + "method": "POST", + "path": "/v1/order_drafts/{id}:selectWorkspace", + "tag": "Order Drafts", + "summary": "Select order workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "orderDrafts.submitConfigure", + "command": "order-drafts submit-configure", + "resource": "order-drafts", + "action": "submit-configure", + "method": "POST", + "path": "/v1/order_drafts/{id}:submitConfiguration", + "tag": "Order Drafts", + "summary": "Submit configure values", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "organizations.addMember", + "command": "organizations add-member", + "resource": "organizations", + "action": "add-member", + "method": "POST", + "path": "/v1/organizations/{id}/members", + "tag": "Organizations", + "summary": "Add organization member", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "organizations.create", + "command": "organizations create", + "resource": "organizations", + "action": "create", + "method": "POST", + "path": "/v1/organizations", + "tag": "Organizations", + "summary": "Create organization", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "organizations.delete", + "command": "organizations delete", + "resource": "organizations", + "action": "delete", + "method": "DELETE", + "path": "/v1/organizations/{id}", + "tag": "Organizations", + "summary": "Delete organization", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "organizations.get", + "command": "organizations get", + "resource": "organizations", + "action": "get", + "method": "GET", + "path": "/v1/organizations/{id}", + "tag": "Organizations", + "summary": "Get organization details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "organizations.list", + "command": "organizations list", + "resource": "organizations", + "action": "list", + "method": "GET", + "path": "/v1/organizations", + "tag": "Organizations", + "summary": "List organizations", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "organizations.listManagedWorkspaces", + "command": "organizations list-managed-workspaces", + "resource": "organizations", + "action": "list-managed-workspaces", + "method": "GET", + "path": "/v1/organizations/{id}/workspaces", + "tag": "Organizations", + "summary": "List managed workspaces", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "organizations.listMembers", + "command": "organizations list-members", + "resource": "organizations", + "action": "list-members", + "method": "GET", + "path": "/v1/organizations/{id}/members", + "tag": "Organizations", + "summary": "List organization members", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "organizations.removeMember", + "command": "organizations remove-member", + "resource": "organizations", + "action": "remove-member", + "method": "DELETE", + "path": "/v1/organizations/{id}/members/{userId}", + "tag": "Organizations", + "summary": "Remove organization member", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "userId", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "organizations.update", + "command": "organizations update", + "resource": "organizations", + "action": "update", + "method": "PATCH", + "path": "/v1/organizations/{id}", + "tag": "Organizations", + "summary": "Update organization", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "organizations.updateMemberRole", + "command": "organizations update-member-role", + "resource": "organizations", + "action": "update-member-role", + "method": "PATCH", + "path": "/v1/organizations/{id}/members/{userId}", + "tag": "Organizations", + "summary": "Update member role", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "userId", + "in": "path", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "packages.create", + "command": "packages create", + "resource": "packages", + "action": "create", + "method": "POST", + "path": "/v1/packages", + "tag": "Packages", + "summary": "Create package", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.createVersion", + "command": "packages create-version", + "resource": "packages", + "action": "create-version", + "method": "POST", + "path": "/v1/packages/{id}/versions", + "tag": "Packages", + "summary": "Create package version", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.delete", + "command": "packages delete", + "resource": "packages", + "action": "delete", + "method": "DELETE", + "path": "/v1/packages/{id}", + "tag": "Packages", + "summary": "Delete package", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "packages.get", + "command": "packages get", + "resource": "packages", + "action": "get", + "method": "GET", + "path": "/v1/packages/{id}", + "tag": "Packages", + "summary": "Get package details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "view", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.getArtifacthubValuesSchema", + "command": "packages get-artifacthub-values-schema", + "resource": "packages", + "action": "get-artifacthub-values-schema", + "method": "GET", + "path": "/v1/packages/artifacthub/{package_id}/versions/{version}/values_schema", + "tag": "Packages", + "summary": "Resolve Artifact Hub chart values + schema", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "package_id", + "in": "path", + "required": true + }, + { + "name": "version", + "in": "path", + "required": true + }, + { + "name": "include_schema", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "packages.getVersion", + "command": "packages get-version", + "resource": "packages", + "action": "get-version", + "method": "GET", + "path": "/v1/packages/{id}/versions/{version_id}", + "tag": "Packages", + "summary": "Get package version details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "version_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.getVersionInputs", + "command": "packages get-version-inputs", + "resource": "packages", + "action": "get-version-inputs", + "method": "GET", + "path": "/v1/packages/{id}/versions/{version_id}/inputs", + "tag": "Packages", + "summary": "Get package version input schema", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "version_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.importPublished", + "command": "packages import-published", + "resource": "packages", + "action": "import-published", + "method": "POST", + "path": "/v1/packages:import", + "tag": "Packages", + "summary": "Import published package", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.list", + "command": "packages list", + "resource": "packages", + "action": "list", + "method": "GET", + "path": "/v1/packages", + "tag": "Packages", + "summary": "List packages", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "view", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "packages.listVersions", + "command": "packages list-versions", + "resource": "packages", + "action": "list-versions", + "method": "GET", + "path": "/v1/packages/{id}/versions", + "tag": "Packages", + "summary": "List package versions", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "previewHostnames.bindFloating", + "command": "preview-hostnames bind-floating", + "resource": "preview-hostnames", + "action": "bind-floating", + "method": "POST", + "path": "/v1/installs/{id}/preview_hostnames:bindFloating", + "tag": "Preview hostnames", + "summary": "Bind floating preview hostname", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "previewHostnames.bindPinned", + "command": "preview-hostnames bind-pinned", + "resource": "preview-hostnames", + "action": "bind-pinned", + "method": "POST", + "path": "/v1/installs/{id}/preview_hostnames:bindPinned", + "tag": "Preview hostnames", + "summary": "Bind pinned preview hostname", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "previewHostnames.delete", + "command": "preview-hostnames delete", + "resource": "preview-hostnames", + "action": "delete", + "method": "DELETE", + "path": "/v1/installs/{id}/preview_hostnames/{preview_hostname_id}", + "tag": "Preview hostnames", + "summary": "Delete preview hostname", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "preview_hostname_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "previewHostnames.get", + "command": "preview-hostnames get", + "resource": "preview-hostnames", + "action": "get", + "method": "GET", + "path": "/v1/installs/{id}/preview_hostnames/{preview_hostname_id}", + "tag": "Preview hostnames", + "summary": "Get preview hostname", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "preview_hostname_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "previewHostnames.list", + "command": "preview-hostnames list", + "resource": "preview-hostnames", + "action": "list", + "method": "GET", + "path": "/v1/installs/{id}/preview_hostnames", + "tag": "Preview hostnames", + "summary": "List preview hostnames", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "binding_kind", + "in": "query", + "required": false + }, + { + "name": "track", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "products.archive", + "command": "products archive", + "resource": "products", + "action": "archive", + "method": "POST", + "path": "/v1/products/{id}:archive", + "tag": "Products", + "summary": "Archive product", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "products.create", + "command": "products create", + "resource": "products", + "action": "create", + "method": "POST", + "path": "/v1/products", + "tag": "Products", + "summary": "Create product", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "products.get", + "command": "products get", + "resource": "products", + "action": "get", + "method": "GET", + "path": "/v1/products/{id}", + "tag": "Products", + "summary": "Get product details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "products.list", + "command": "products list", + "resource": "products", + "action": "list", + "method": "GET", + "path": "/v1/products", + "tag": "Products", + "summary": "List products in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "products.unarchive", + "command": "products unarchive", + "resource": "products", + "action": "unarchive", + "method": "POST", + "path": "/v1/products/{id}:unarchive", + "tag": "Products", + "summary": "Unarchive product", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "products.update", + "command": "products update", + "resource": "products", + "action": "update", + "method": "PATCH", + "path": "/v1/products/{id}", + "tag": "Products", + "summary": "Update product", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "quotas.get", + "command": "quotas get", + "resource": "quotas", + "action": "get", + "method": "GET", + "path": "/v1/quotas/{metric}", + "tag": "Quotas", + "summary": "Get quota usage for a specific metric", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "metric", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "quotas.list", + "command": "quotas list", + "resource": "quotas", + "action": "list", + "method": "GET", + "path": "/v1/quotas", + "tag": "Quotas", + "summary": "List quota usage for the authenticated user", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cluster_id", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "regions.create", + "command": "regions create", + "resource": "regions", + "action": "create", + "method": "POST", + "path": "/v1/regions", + "tag": "Regions", + "summary": "Create region", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "regions.list", + "command": "regions list", + "resource": "regions", + "action": "list", + "method": "GET", + "path": "/v1/regions", + "tag": "Regions", + "summary": "List regions in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "registry.createCredential", + "command": "registry create-credential", + "resource": "registry", + "action": "create-credential", + "method": "POST", + "path": "/v1/registry_connections", + "tag": "Registry", + "summary": "Create registry credential", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "registry.deleteCredential", + "command": "registry delete-credential", + "resource": "registry", + "action": "delete-credential", + "method": "DELETE", + "path": "/v1/registry_connections/{id}", + "tag": "Registry", + "summary": "Delete registry credential", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "registry.listCredentials", + "command": "registry list-credentials", + "resource": "registry", + "action": "list-credentials", + "method": "GET", + "path": "/v1/registry_connections", + "tag": "Registry", + "summary": "List registry credentials", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "repositories.get", + "command": "repositories get", + "resource": "repositories", + "action": "get", + "method": "GET", + "path": "/v1/repositories/{id}", + "tag": "Repositories", + "summary": "Get repository details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "view", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "repositories.list", + "command": "repositories list", + "resource": "repositories", + "action": "list", + "method": "GET", + "path": "/v1/repositories", + "tag": "Repositories", + "summary": "List repositories in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "purpose", + "in": "query", + "required": false + }, + { + "name": "view", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "repositoryChangeRequests.accept", + "command": "repository-change-requests accept", + "resource": "repository-change-requests", + "action": "accept", + "method": "POST", + "path": "/v1/repository_change_requests/{id}:accept", + "tag": "Repository change requests", + "summary": "Accept repository change request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "repositoryChangeRequests.create", + "command": "repository-change-requests create", + "resource": "repository-change-requests", + "action": "create", + "method": "POST", + "path": "/v1/repository_change_requests", + "tag": "Repository change requests", + "summary": "Create repository change request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "repositoryChangeRequests.createToken", + "command": "repository-change-requests create-token", + "resource": "repository-change-requests", + "action": "create-token", + "method": "POST", + "path": "/v1/repository_change_requests/{id}:createToken", + "tag": "Repository change requests", + "summary": "Create repository change request token", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "repositoryChangeRequests.get", + "command": "repository-change-requests get", + "resource": "repository-change-requests", + "action": "get", + "method": "GET", + "path": "/v1/repository_change_requests/{id}", + "tag": "Repository change requests", + "summary": "Get repository change request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "repositoryChangeRequests.list", + "command": "repository-change-requests list", + "resource": "repository-change-requests", + "action": "list", + "method": "GET", + "path": "/v1/repository_change_requests", + "tag": "Repository change requests", + "summary": "List repository change requests", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "parent_repository", + "in": "query", + "required": false + }, + { + "name": "fork_repository", + "in": "query", + "required": false + }, + { + "name": "agent", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "repositoryChangeRequests.reject", + "command": "repository-change-requests reject", + "resource": "repository-change-requests", + "action": "reject", + "method": "POST", + "path": "/v1/repository_change_requests/{id}:reject", + "tag": "Repository change requests", + "summary": "Reject repository change request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "repositoryChangeRequests.withdraw", + "command": "repository-change-requests withdraw", + "resource": "repository-change-requests", + "action": "withdraw", + "method": "POST", + "path": "/v1/repository_change_requests/{id}:withdraw", + "tag": "Repository change requests", + "summary": "Withdraw repository change request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.accessVersion", + "command": "secrets access-version", + "resource": "secrets", + "action": "access-version", + "method": "POST", + "path": "/v1/secrets/{id}/versions/{vid}:access", + "tag": "Secrets", + "summary": "Access secret version plaintext", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "vid", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.create", + "command": "secrets create", + "resource": "secrets", + "action": "create", + "method": "POST", + "path": "/v1/secrets", + "tag": "Secrets", + "summary": "Create secret", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.createVersion", + "command": "secrets create-version", + "resource": "secrets", + "action": "create-version", + "method": "POST", + "path": "/v1/secrets/{id}/versions", + "tag": "Secrets", + "summary": "Create secret version", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.delete", + "command": "secrets delete", + "resource": "secrets", + "action": "delete", + "method": "DELETE", + "path": "/v1/secrets/{id}", + "tag": "Secrets", + "summary": "Delete secret", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "force", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.destroyVersion", + "command": "secrets destroy-version", + "resource": "secrets", + "action": "destroy-version", + "method": "POST", + "path": "/v1/secrets/{id}/versions/{vid}:destroy", + "tag": "Secrets", + "summary": "Destroy secret version", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "vid", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.disableVersion", + "command": "secrets disable-version", + "resource": "secrets", + "action": "disable-version", + "method": "POST", + "path": "/v1/secrets/{id}/versions/{vid}:disable", + "tag": "Secrets", + "summary": "Disable secret version", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "vid", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.enableVersion", + "command": "secrets enable-version", + "resource": "secrets", + "action": "enable-version", + "method": "POST", + "path": "/v1/secrets/{id}/versions/{vid}:enable", + "tag": "Secrets", + "summary": "Enable a disabled secret version", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "vid", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.get", + "command": "secrets get", + "resource": "secrets", + "action": "get", + "method": "GET", + "path": "/v1/secrets/{id}", + "tag": "Secrets", + "summary": "Get secret", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.getVersion", + "command": "secrets get-version", + "resource": "secrets", + "action": "get-version", + "method": "GET", + "path": "/v1/secrets/{id}/versions/{vid}", + "tag": "Secrets", + "summary": "Get secret version", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "vid", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.list", + "command": "secrets list", + "resource": "secrets", + "action": "list", + "method": "GET", + "path": "/v1/secrets", + "tag": "Secrets", + "summary": "List secrets", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "kind", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.listVersions", + "command": "secrets list-versions", + "resource": "secrets", + "action": "list-versions", + "method": "GET", + "path": "/v1/secrets/{id}/versions", + "tag": "Secrets", + "summary": "List secret versions", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "secrets.undelete", + "command": "secrets undelete", + "resource": "secrets", + "action": "undelete", + "method": "POST", + "path": "/v1/secrets/{id}:undelete", + "tag": "Secrets", + "summary": "Restore a soft-deleted secret", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.update", + "command": "secrets update", + "resource": "secrets", + "action": "update", + "method": "PATCH", + "path": "/v1/secrets/{id}", + "tag": "Secrets", + "summary": "Update secret", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "secrets.validateToken", + "command": "secrets validate-token", + "resource": "secrets", + "action": "validate-token", + "method": "POST", + "path": "/v1/secrets/validate_token", + "tag": "Secrets", + "summary": "Validate a provider token", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "snippets.create", + "command": "snippets create", + "resource": "snippets", + "action": "create", + "method": "POST", + "path": "/v1/snippets", + "tag": "Snippets", + "summary": "Create snippet", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "snippets.createRun", + "command": "snippets create-run", + "resource": "snippets", + "action": "create-run", + "method": "POST", + "path": "/v1/snippets/{id}/runs", + "tag": "Snippets", + "summary": "Create snippet run", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "snippets.delete", + "command": "snippets delete", + "resource": "snippets", + "action": "delete", + "method": "DELETE", + "path": "/v1/snippets/{id}", + "tag": "Snippets", + "summary": "Delete snippet", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "snippets.execute", + "command": "snippets execute", + "resource": "snippets", + "action": "execute", + "method": "POST", + "path": "/v1/snippets:execute", + "tag": "Snippets", + "summary": "Execute ad-hoc snippet code", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "snippets.executeStored", + "command": "snippets execute-stored", + "resource": "snippets", + "action": "execute-stored", + "method": "POST", + "path": "/v1/snippets/{id}:execute", + "tag": "Snippets", + "summary": "Execute stored snippet", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "snippets.get", + "command": "snippets get", + "resource": "snippets", + "action": "get", + "method": "GET", + "path": "/v1/snippets/{id}", + "tag": "Snippets", + "summary": "Get snippet details", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "snippets.getRun", + "command": "snippets get-run", + "resource": "snippets", + "action": "get-run", + "method": "GET", + "path": "/v1/snippets/{id}/runs/{run_id}", + "tag": "Snippets", + "summary": "Get snippet run", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "run_id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "snippets.getUsage", + "command": "snippets get-usage", + "resource": "snippets", + "action": "get-usage", + "method": "GET", + "path": "/v1/snippets/{id}:usage", + "tag": "Snippets", + "summary": "Get snippet dashboard usage", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "snippets.list", + "command": "snippets list", + "resource": "snippets", + "action": "list", + "method": "GET", + "path": "/v1/snippets", + "tag": "Snippets", + "summary": "List snippets in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "snippets.listRuns", + "command": "snippets list-runs", + "resource": "snippets", + "action": "list-runs", + "method": "GET", + "path": "/v1/snippets/{id}/runs", + "tag": "Snippets", + "summary": "List snippet runs", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "state", + "in": "query", + "required": false + }, + { + "name": "view", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "snippets.listUsage", + "command": "snippets list-usage", + "resource": "snippets", + "action": "list-usage", + "method": "GET", + "path": "/v1/snippets:usage", + "tag": "Snippets", + "summary": "List snippet dashboard usage in workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "snippets.update", + "command": "snippets update", + "resource": "snippets", + "action": "update", + "method": "PATCH", + "path": "/v1/snippets/{id}", + "tag": "Snippets", + "summary": "Update snippet", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "workspaces.addMember", + "command": "workspaces add-member", + "resource": "workspaces", + "action": "add-member", + "method": "POST", + "path": "/v1/workspaces/{id}/members", + "tag": "Workspaces", + "summary": "Add workspace member", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.cancelSubscription", + "command": "workspaces cancel-subscription", + "resource": "workspaces", + "action": "cancel-subscription", + "method": "POST", + "path": "/v1/workspaces/{id}/subscription:cancel", + "tag": "Workspaces", + "summary": "Cancel workspace subscription", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "workspaces.changeSubscriptionTier", + "command": "workspaces change-subscription-tier", + "resource": "workspaces", + "action": "change-subscription-tier", + "method": "POST", + "path": "/v1/workspaces/{id}/subscription:changeTier", + "tag": "Workspaces", + "summary": "Change workspace subscription tier", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "workspaces.create", + "command": "workspaces create", + "resource": "workspaces", + "action": "create", + "method": "POST", + "path": "/v1/workspaces", + "tag": "Workspaces", + "summary": "Create workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [] + }, + { + "operation_id": "workspaces.delete", + "command": "workspaces delete", + "resource": "workspaces", + "action": "delete", + "method": "DELETE", + "path": "/v1/workspaces/{id}", + "tag": "Workspaces", + "summary": "Delete workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "workspaces.get", + "command": "workspaces get", + "resource": "workspaces", + "action": "get", + "method": "GET", + "path": "/v1/workspaces/{id}", + "tag": "Workspaces", + "summary": "Get workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "workspaces.getAccessState", + "command": "workspaces get-access-state", + "resource": "workspaces", + "action": "get-access-state", + "method": "GET", + "path": "/v1/workspaces/{id}/access_state", + "tag": "Workspaces", + "summary": "Get workspace access state", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.getSubscription", + "command": "workspaces get-subscription", + "resource": "workspaces", + "action": "get-subscription", + "method": "GET", + "path": "/v1/workspaces/{id}/subscription", + "tag": "Workspaces", + "summary": "Get workspace subscription", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.getSubscriptionChangeRequest", + "command": "workspaces get-subscription-change-request", + "resource": "workspaces", + "action": "get-subscription-change-request", + "method": "GET", + "path": "/v1/workspaces/{id}/subscription/change_requests/{req_id}", + "tag": "Workspaces", + "summary": "Get subscription change request", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "req_id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.list", + "command": "workspaces list", + "resource": "workspaces", + "action": "list", + "method": "GET", + "path": "/v1/workspaces", + "tag": "Workspaces", + "summary": "List workspaces", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + } + ] + }, + { + "operation_id": "workspaces.listMembers", + "command": "workspaces list-members", + "resource": "workspaces", + "action": "list-members", + "method": "GET", + "path": "/v1/workspaces/{id}/members", + "tag": "Workspaces", + "summary": "List workspace members", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.listSubscriptionChangeRequests", + "command": "workspaces list-subscription-change-requests", + "resource": "workspaces", + "action": "list-subscription-change-requests", + "method": "GET", + "path": "/v1/workspaces/{id}/subscription/change_requests", + "tag": "Workspaces", + "summary": "List subscription change requests", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "cursor", + "in": "query", + "required": false + }, + { + "name": "limit", + "in": "query", + "required": false + }, + { + "name": "akua-context", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.reactivateSubscription", + "command": "workspaces reactivate-subscription", + "resource": "workspaces", + "action": "reactivate-subscription", + "method": "POST", + "path": "/v1/workspaces/{id}/subscription:reactivate", + "tag": "Workspaces", + "summary": "Reactivate workspace subscription", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "workspaces.removeMember", + "command": "workspaces remove-member", + "resource": "workspaces", + "action": "remove-member", + "method": "DELETE", + "path": "/v1/workspaces/{id}/members/{userId}", + "tag": "Workspaces", + "summary": "Remove workspace member", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "userId", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaces.update", + "command": "workspaces update", + "resource": "workspaces", + "action": "update", + "method": "PATCH", + "path": "/v1/workspaces/{id}", + "tag": "Workspaces", + "summary": "Update workspace", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "if-match", + "in": "header", + "required": true + } + ] + }, + { + "operation_id": "workspaces.updateMember", + "command": "workspaces update-member", + "resource": "workspaces", + "action": "update-member", + "method": "PATCH", + "path": "/v1/workspaces/{id}/members/{userId}", + "tag": "Workspaces", + "summary": "Update workspace member role", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "userId", + "in": "path", + "required": true + }, + { + "name": "akua-context", + "in": "header", + "required": false + }, + { + "name": "idempotency-key", + "in": "header", + "required": false + } + ] + }, + { + "operation_id": "workspaceSubdomains.get", + "command": "workspace-subdomains get", + "resource": "workspace-subdomains", + "action": "get", + "method": "GET", + "path": "/v1/workspaces/{id}/subdomain", + "tag": "Workspace subdomains", + "summary": "Get workspace subdomain", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + } + ] + }, + { + "operation_id": "workspaceSubdomains.setName", + "command": "workspace-subdomains set-name", + "resource": "workspace-subdomains", + "action": "set-name", + "method": "POST", + "path": "/v1/workspaces/{id}/subdomain:setName", + "tag": "Workspace subdomains", + "summary": "Set workspace subdomain name", + "visibility": "PUBLIC", + "requires_auth": true, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true + }, + { + "name": "if-match", + "in": "header", + "required": true + }, + { + "name": "idempotency-key", + "in": "header", + "required": true + } + ] + } +] as const satisfies readonly CommandDefinition[]; diff --git a/src/runtime/errors.ts b/src/runtime/errors.ts new file mode 100644 index 0000000..5b4250e --- /dev/null +++ b/src/runtime/errors.ts @@ -0,0 +1,93 @@ +import { ExitCodes, type ExitCode } from "./exit-codes"; + +export interface NextStep { + command: string; + description?: string; +} + +export interface CliErrorOptions { + type: string; + code: string; + message: string; + status?: number; + path?: readonly string[]; + requestId?: string; + retryAfter?: string | number | null; + nextSteps?: readonly NextStep[]; + exitCode?: ExitCode; +} + +export class AkuaCliError extends Error { + readonly type: string; + readonly code: string; + readonly status?: number; + readonly path: readonly string[]; + readonly requestId?: string; + readonly retryAfter?: string | number | null; + readonly nextSteps: readonly NextStep[]; + readonly exitCode: ExitCode; + + constructor(options: CliErrorOptions) { + super(options.message); + this.name = "AkuaCliError"; + this.type = options.type; + this.code = options.code; + this.status = options.status; + this.path = options.path ?? []; + this.requestId = options.requestId; + this.retryAfter = options.retryAfter; + this.nextSteps = options.nextSteps ?? []; + this.exitCode = options.exitCode ?? exitCodeForStatus(options.status); + } + + toPayload() { + return { + error: { + type: this.type, + code: this.code, + status: this.status, + message: this.message, + path: this.path.length > 0 ? this.path : undefined, + request_id: this.requestId, + retry_after: this.retryAfter ?? undefined, + next_steps: this.nextSteps.length > 0 ? this.nextSteps : undefined, + }, + }; + } +} + +export function usageError(message: string): AkuaCliError { + return new AkuaCliError({ + type: "usage_error", + code: "AKUA_USAGE_ERROR", + message, + exitCode: ExitCodes.Usage, + nextSteps: [{ command: "akua --help" }], + }); +} + +export function commandNotImplemented(operationId: string): AkuaCliError { + return new AkuaCliError({ + type: "not_implemented", + code: "AKUA_COMMAND_NOT_IMPLEMENTED", + message: `Operation ${operationId} is registered but command execution is not implemented yet.`, + exitCode: ExitCodes.Usage, + nextSteps: [ + { command: "akua commands" }, + { command: `akua commands --operation-id ${operationId}` }, + ], + }); +} + +function exitCodeForStatus(status: number | undefined): ExitCode { + if (status === 401) { + return ExitCodes.AuthRequired; + } + if (status === 409) { + return ExitCodes.Conflict; + } + if (status === 429 || (status !== undefined && status >= 500)) { + return ExitCodes.Retryable; + } + return ExitCodes.Runtime; +} diff --git a/src/runtime/exit-codes.ts b/src/runtime/exit-codes.ts new file mode 100644 index 0000000..79ba564 --- /dev/null +++ b/src/runtime/exit-codes.ts @@ -0,0 +1,11 @@ +export const ExitCodes = { + Ok: 0, + Runtime: 1, + Usage: 2, + AuthRequired: 3, + ConfirmationRequired: 4, + Conflict: 5, + Retryable: 6, +} as const; + +export type ExitCode = (typeof ExitCodes)[keyof typeof ExitCodes]; diff --git a/src/runtime/mode.ts b/src/runtime/mode.ts new file mode 100644 index 0000000..0c55e39 --- /dev/null +++ b/src/runtime/mode.ts @@ -0,0 +1,126 @@ +import { usageError } from "./errors"; + +export type OutputMode = "human" | "agent" | "json" | "quiet"; + +export interface OutputModeInput { + argv: readonly string[]; + env: Record; + stdoutIsTTY?: boolean; +} + +const AGENT_ENV_VARS = [ + "CODEX_SANDBOX", + "CODEX_CLI", + "OPENAI_CODEX", + "CLAUDECODE", + "CLAUDE_CODE", + "CURSOR_AGENT", + "AIDER", + "DEVIN", + "OPENCODE", + "AMP", + "CODY_AGENT", + "REPLIT_AGENT", + "WINDSURF_AGENT", +]; + +const AUTOMATION_ENV_VARS = [ + "CI", + "GITHUB_ACTIONS", + "GITLAB_CI", + "BUILDKITE", + "CIRCLECI", + "JENKINS_URL", + "TEAMCITY_VERSION", + "TF_BUILD", +]; + +const EXPLICIT_OUTPUT_MODES = ["human", "agent", "json", "quiet"] as const; + +export function detectOutputMode(input: OutputModeInput): OutputMode { + const explicit = readExplicitMode(input.argv, input.env); + if (explicit) { + return explicit; + } + + if (hasAnyEnv(input.env, AGENT_ENV_VARS) || hasAnyEnv(input.env, AUTOMATION_ENV_VARS)) { + return "agent"; + } + + if (input.stdoutIsTTY === false) { + return "agent"; + } + + return "human"; +} + +export function isAutomationMode(mode: OutputMode): boolean { + return mode === "agent" || mode === "json" || mode === "quiet"; +} + +function readExplicitMode(argv: readonly string[], env: Record): OutputMode | undefined { + const outputFlag = readOutputFlag(argv); + const envMode = readEnvOutputMode(env); + + if (argv.includes("--json")) { + return "json"; + } + if (argv.includes("--quiet") || argv.includes("-q")) { + return "quiet"; + } + + return outputFlag ?? envMode; +} + +function readOutputFlag(argv: readonly string[]): OutputMode | undefined { + let mode: OutputMode | undefined; + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (value === "--output" || value === "-o") { + const raw = argv[index + 1]; + if (raw === undefined || raw === "" || raw.startsWith("-")) { + throw usageError(`Missing value for ${value}. Expected one of: ${EXPLICIT_OUTPUT_MODES.join(", ")}.`); + } + mode = parseOutputMode(raw); + index += 1; + continue; + } + if (value.startsWith("--output=") || value.startsWith("-o=")) { + const [flag, raw] = splitFlagAssignment(value); + if (raw === "") { + throw usageError(`Missing value for ${flag}. Expected one of: ${EXPLICIT_OUTPUT_MODES.join(", ")}.`); + } + mode = parseOutputMode(raw); + } + } + return mode; +} + +function readEnvOutputMode(env: Record): OutputMode | undefined { + if (env.AKUA_OUTPUT === undefined) { + return undefined; + } + if (env.AKUA_OUTPUT === "") { + throw usageError(`Invalid AKUA_OUTPUT value: . Expected one of: ${EXPLICIT_OUTPUT_MODES.join(", ")}.`); + } + return parseOutputMode(env.AKUA_OUTPUT, "AKUA_OUTPUT"); +} + +function parseOutputMode(value: string, source = "--output"): OutputMode { + if (EXPLICIT_OUTPUT_MODES.includes(value as OutputMode)) { + return value as OutputMode; + } + throw usageError(`Invalid ${source} value: ${value}. Expected one of: ${EXPLICIT_OUTPUT_MODES.join(", ")}.`); +} + +function splitFlagAssignment(value: string): [string, string] { + const separator = value.indexOf("="); + return [value.slice(0, separator), value.slice(separator + 1)]; +} + +function hasAnyEnv(env: Record, names: readonly string[]): boolean { + return names.some((name) => { + const value = env[name]; + return value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false"; + }); +} diff --git a/src/runtime/registry.ts b/src/runtime/registry.ts new file mode 100644 index 0000000..e783ca4 --- /dev/null +++ b/src/runtime/registry.ts @@ -0,0 +1,19 @@ +export interface CommandDefinition { + operation_id: string; + command: string; + resource: string; + action: string; + method: string; + path: string; + tag: string; + summary: string; + visibility: "PUBLIC"; + requires_auth: boolean; + parameters: readonly CommandParameter[]; +} + +export interface CommandParameter { + name: string; + in: "path" | "query" | "header" | "cookie"; + required: boolean; +} diff --git a/src/runtime/render.ts b/src/runtime/render.ts new file mode 100644 index 0000000..a2a7045 --- /dev/null +++ b/src/runtime/render.ts @@ -0,0 +1,151 @@ +import type { AkuaCliError, NextStep } from "./errors"; +import type { OutputMode } from "./mode"; + +export interface RenderEnvelope { + command: string; + status?: "ok"; + observations?: readonly string[]; + data?: unknown; + next_steps?: readonly NextStep[]; +} + +export function renderSuccess(envelope: RenderEnvelope, mode: OutputMode): string { + if (mode === "quiet") { + return ""; + } + + const payload = { status: "ok" as const, ...envelope }; + if (mode === "json") { + return `${JSON.stringify(payload, null, 2)}\n`; + } + if (mode === "agent") { + return renderToon(payload); + } + + return renderHuman(payload); +} + +export function renderError(error: AkuaCliError, mode: OutputMode): string { + const payload = error.toPayload(); + if (mode === "quiet") { + return ""; + } + if (mode === "json") { + return `${JSON.stringify(payload, null, 2)}\n`; + } + if (mode === "agent") { + return renderToon(payload); + } + + const lines = [`Error: ${error.message}`]; + if (error.requestId) { + lines.push(`Request ID: ${error.requestId}`); + } + if (error.nextSteps.length > 0) { + lines.push("", "Next steps:"); + for (const step of error.nextSteps) { + lines.push(` ${step.command}`); + } + } + return `${lines.join("\n")}\n`; +} + +export function renderToon(value: unknown): string { + return `${renderValue(value, 0).join("\n")}\n`; +} + +function renderHuman(envelope: RenderEnvelope): string { + const lines: string[] = []; + if (envelope.observations) { + lines.push(...envelope.observations); + } + if (envelope.data !== undefined) { + if (Array.isArray(envelope.data)) { + lines.push(...renderHumanTable(envelope.data)); + } else { + lines.push(JSON.stringify(envelope.data, null, 2)); + } + } + if (envelope.next_steps && envelope.next_steps.length > 0) { + lines.push("", "Next steps:"); + for (const step of envelope.next_steps) { + lines.push(` ${step.command}`); + } + } + return `${lines.join("\n")}\n`; +} + +function renderHumanTable(rows: readonly unknown[]): string[] { + if (rows.length === 0) { + return ["No results."]; + } + const objects = rows.filter(isRecord); + if (objects.length !== rows.length) { + return rows.map((row) => String(row)); + } + const keys = Object.keys(objects[0] ?? {}).slice(0, 5); + const widths = keys.map((key) => Math.max(key.length, ...objects.map((row) => String(row[key] ?? "").length))); + const header = keys.map((key, index) => key.padEnd(widths[index])).join(" "); + const divider = widths.map((width) => "-".repeat(width)).join(" "); + const body = objects.map((row) => keys.map((key, index) => String(row[key] ?? "").padEnd(widths[index])).join(" ")); + return [header, divider, ...body]; +} + +function renderValue(value: unknown, indent: number, key?: string): string[] { + const prefix = " ".repeat(indent); + if (value === undefined) { + return []; + } + if (value === null || typeof value !== "object") { + return [`${prefix}${key ? `${key}: ` : ""}${String(value)}`]; + } + if (Array.isArray(value)) { + return renderArray(value, indent, key); + } + + const lines: string[] = []; + if (key) { + lines.push(`${prefix}${key}:`); + } + for (const [childKey, childValue] of Object.entries(value as Record)) { + lines.push(...renderValue(childValue, key ? indent + 2 : indent, childKey)); + } + return lines; +} + +function renderArray(values: readonly unknown[], indent: number, key = "items"): string[] { + const prefix = " ".repeat(indent); + if (values.length === 0) { + return [`${prefix}${key}[0]:`]; + } + + if (values.every(isRecord)) { + const rows = values as readonly Record[]; + const keys = Object.keys(rows[0] ?? {}).filter((candidate) => + rows.every((row) => row[candidate] === undefined || row[candidate] === null || typeof row[candidate] !== "object"), + ); + if (keys.length > 0) { + return [ + `${prefix}${key}[${rows.length}]{${keys.join(",")}}:`, + ...rows.map((row) => `${prefix} ${keys.map((field) => escapeCell(row[field])).join(",")}`), + ]; + } + } + + return [`${prefix}${key}[${values.length}]:`, ...values.map((item) => `${prefix} ${String(item)}`)]; +} + +function escapeCell(value: unknown): string { + if (value === undefined || value === null) { + return ""; + } + const text = String(value); + if (/[\n,]/.test(text)) { + return JSON.stringify(text); + } + return text; +} + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === "object" && !Array.isArray(value); +} diff --git a/test/cli.test.ts b/test/cli.test.ts new file mode 100644 index 0000000..a7d6951 --- /dev/null +++ b/test/cli.test.ts @@ -0,0 +1,124 @@ +import { describe, expect, test } from "bun:test"; + +describe("akua entrypoint", () => { + test("fails loudly on unknown flags", async () => { + const { stdout, exitCode } = await runAkua(["commands", "--bogus", "--output", "json"]); + expect(exitCode).toBe(2); + expect(JSON.parse(stdout)).toMatchObject({ + error: { + type: "usage_error", + code: "AKUA_USAGE_ERROR", + message: "Unknown flag: --bogus", + }, + }); + }); + + test("fails invalid explicit output modes before routing", async () => { + const { stdout, exitCode } = await runAkua(["--output", "yaml", "--version"]); + expect(exitCode).toBe(2); + expect(stdout).toContain("Invalid --output value: yaml"); + }); + + test("rejects undocumented toon output mode", async () => { + const flag = await runAkua(["--output", "toon", "--version"]); + expect(flag.exitCode).toBe(2); + expect(flag.stdout).toContain("Invalid --output value: toon"); + + const env = await runAkua(["--version"], { AKUA_OUTPUT: "toon" }); + expect(env.exitCode).toBe(2); + expect(env.stdout).toContain("Invalid AKUA_OUTPUT value: toon"); + }); + + test("fails missing explicit output mode values before routing", async () => { + const { stdout, exitCode } = await runAkua(["--output", "--version"]); + expect(exitCode).toBe(2); + expect(stdout).toContain("Missing value for --output"); + }); + + test("fails invalid AKUA_OUTPUT values before routing", async () => { + const { stdout, exitCode } = await runAkua(["--version"], { AKUA_OUTPUT: "yaml" }); + expect(exitCode).toBe(2); + expect(stdout).toContain("Invalid AKUA_OUTPUT value: yaml"); + }); + + test("requires commands filter values", async () => { + const { stdout, exitCode } = await runAkua(["commands", "--operation-id", "--json"]); + expect(exitCode).toBe(2); + expect(JSON.parse(stdout)).toMatchObject({ + error: { + type: "usage_error", + code: "AKUA_USAGE_ERROR", + message: "Missing value for --operation-id.", + }, + }); + }); + + test("requires resource filter values", async () => { + const { stdout, exitCode } = await runAkua(["commands", "--resource=", "--json"]); + expect(exitCode).toBe(2); + expect(JSON.parse(stdout)).toMatchObject({ + error: { + message: "Missing value for --resource.", + }, + }); + }); + + test("requires positive integer command limits", async () => { + const invalid = await runAkua(["commands", "--limit", "banana", "--json"]); + expect(invalid.exitCode).toBe(2); + expect(JSON.parse(invalid.stdout)).toMatchObject({ + error: { + message: "Invalid value for --limit: banana. Expected a positive integer.", + }, + }); + + const zero = await runAkua(["commands", "--limit=0", "--json"]); + expect(zero.exitCode).toBe(2); + expect(JSON.parse(zero.stdout)).toMatchObject({ + error: { + message: "Invalid value for --limit: 0. Expected a positive integer.", + }, + }); + }); + + test("rejects unexpected commands positional arguments", async () => { + const resource = await runAkua(["commands", "workspaces", "--json"]); + expect(resource.exitCode).toBe(2); + expect(JSON.parse(resource.stdout)).toMatchObject({ + error: { + type: "usage_error", + code: "AKUA_USAGE_ERROR", + message: "Unexpected argument for commands: workspaces", + }, + }); + + const extra = await runAkua(["commands", "--limit", "5", "extra", "--json"]); + expect(extra.exitCode).toBe(2); + expect(JSON.parse(extra.stdout)).toMatchObject({ + error: { + message: "Unexpected argument for commands: extra", + }, + }); + }); +}); + +async function runAkua(args: readonly string[], env: Record = {}) { + const childEnv = { ...process.env, ...env }; + if (!("AKUA_OUTPUT" in env)) { + delete childEnv.AKUA_OUTPUT; + } + + const proc = Bun.spawn({ + cmd: ["bun", "src/bin/akua.ts", ...args], + stdout: "pipe", + stderr: "pipe", + env: childEnv, + }); + + const [stdout, stderr, exitCode] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + proc.exited, + ]); + return { stdout, stderr, exitCode }; +} diff --git a/test/fetch-openapi.test.ts b/test/fetch-openapi.test.ts new file mode 100644 index 0000000..76d5e25 --- /dev/null +++ b/test/fetch-openapi.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, test } from "bun:test"; + +import { DEFAULT_OPENAPI_URL, resolveSpecUrl, validateOpenApiDocument } from "../scripts/fetch-openapi"; + +describe("OpenAPI fetch guard", () => { + test("defaults to the production public OpenAPI endpoint", () => { + expect(resolveSpecUrl(undefined).href).toBe(DEFAULT_OPENAPI_URL); + }); + + test("rejects non-https URLs", () => { + expect(() => resolveSpecUrl("http://api.akua.dev/v1/openapi.json")).toThrow("https"); + }); + + test("validates the minimum OpenAPI document shape", () => { + expect(() => validateOpenApiDocument({ openapi: "3.1.0", paths: {} })).not.toThrow(); + expect(() => validateOpenApiDocument({ openapi: "2.0", paths: {} })).toThrow("OpenAPI 3.x"); + }); +}); diff --git a/test/generate-commands.test.ts b/test/generate-commands.test.ts new file mode 100644 index 0000000..085f6c2 --- /dev/null +++ b/test/generate-commands.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, test } from "bun:test"; + +import { collectPublicCommands } from "../scripts/generate-commands"; + +describe("collectPublicCommands", () => { + test("includes public operations and excludes non-public operations", () => { + const commands = collectPublicCommands({ + paths: { + "/v1/workspaces": { + get: { + "x-platform-visibility": "PUBLIC", + operationId: "workspaces.list", + tags: ["Workspaces"], + summary: "List workspaces", + security: [{ BearerAuth: [] }], + parameters: [{ name: "limit", in: "query", required: false }], + }, + }, + "/v1/admin/users": { + get: { + "x-platform-visibility": "ADMIN", + operationId: "adminAccess.listUsers", + }, + }, + }, + }); + + expect(commands).toHaveLength(1); + expect(commands[0]).toMatchObject({ + operation_id: "workspaces.list", + command: "workspaces list", + visibility: "PUBLIC", + requires_auth: true, + }); + }); +}); diff --git a/test/mode.test.ts b/test/mode.test.ts new file mode 100644 index 0000000..0315e90 --- /dev/null +++ b/test/mode.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, test } from "bun:test"; + +import { detectOutputMode } from "../src/runtime/mode"; + +describe("detectOutputMode", () => { + test("prefers explicit json flag", () => { + expect(detectOutputMode({ argv: ["--json"], env: { CODEX_SANDBOX: "1" }, stdoutIsTTY: true })).toBe("json"); + }); + + test("detects known coding agent environments", () => { + expect(detectOutputMode({ argv: [], env: { CODEX_SANDBOX: "1" }, stdoutIsTTY: true })).toBe("agent"); + }); + + test("detects CI and non-tty automation", () => { + expect(detectOutputMode({ argv: [], env: { CI: "true" }, stdoutIsTTY: true })).toBe("agent"); + expect(detectOutputMode({ argv: [], env: {}, stdoutIsTTY: false })).toBe("agent"); + }); + + test("uses human output for interactive sessions without automation signals", () => { + expect(detectOutputMode({ argv: [], env: {}, stdoutIsTTY: true })).toBe("human"); + }); + + test("rejects undocumented output aliases", () => { + expect(() => detectOutputMode({ argv: ["--output", "toon"], env: {}, stdoutIsTTY: true })).toThrow( + "Invalid --output value: toon", + ); + expect(() => detectOutputMode({ argv: [], env: { AKUA_OUTPUT: "toon" }, stdoutIsTTY: true })).toThrow( + "Invalid AKUA_OUTPUT value: toon", + ); + }); +}); diff --git a/test/render.test.ts b/test/render.test.ts new file mode 100644 index 0000000..ce68200 --- /dev/null +++ b/test/render.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, test } from "bun:test"; + +import { AkuaCliError } from "../src/runtime/errors"; +import { renderError, renderSuccess } from "../src/runtime/render"; + +describe("renderSuccess", () => { + test("renders compact table-shaped agent output", () => { + const output = renderSuccess( + { + command: "akua commands", + observations: ["2 operations shown."], + data: [ + { operation_id: "workspaces.list", command: "workspaces list" }, + { operation_id: "workspaces.get", command: "workspaces get" }, + ], + next_steps: [{ command: "akua commands --json" }], + }, + "agent", + ); + + expect(output).toContain("status: ok"); + expect(output).toContain("data[2]{operation_id,command}:"); + expect(output).toContain("next_steps[1]{command}:"); + }); + + test("renders deterministic json", () => { + const output = renderSuccess({ command: "akua", data: { version: "0.0.0" } }, "json"); + expect(JSON.parse(output)).toEqual({ status: "ok", command: "akua", data: { version: "0.0.0" } }); + }); +}); + +describe("renderError", () => { + test("preserves structured API error fields", () => { + const output = renderError( + new AkuaCliError({ + type: "validation_error", + code: "INVALID_ARGUMENT", + status: 400, + message: "workspace_id is required", + path: ["body", "workspace_id"], + requestId: "req_123", + nextSteps: [{ command: "akua workspaces list" }], + }), + "json", + ); + + expect(JSON.parse(output)).toEqual({ + error: { + type: "validation_error", + code: "INVALID_ARGUMENT", + status: 400, + message: "workspace_id is required", + path: ["body", "workspace_id"], + request_id: "req_123", + next_steps: [{ command: "akua workspaces list" }], + }, + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b01d504 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2023", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["bun-types"] + }, + "include": ["scripts/**/*.ts", "src/**/*.ts", "test/**/*.ts"] +}