openapi: 3.1.0 info: title: Davinci Public API version: 2.0.0 description: | Public Routing Server API contract for Davinci integrations and official SDKs. Most operations live on the canonical `/api/v2/projects` mount and accept a personal access token (`dav_ak_live_…` / `dav_ak_test_…`) or browser access token. Evaluation-run creation is the deliberate exception: it accepts only a `purpose=automation` grant issued to a running Code execution. Project membership and role are checked on every user call, and an API key is additionally bounded by the permission ceiling derived from its scopes — a key can never exceed what its owner can do, and usually does less. Collaboration operations (invitations, membership changes, ownership transfer) are deliberately absent: they require a browser session and are not part of the programmatic surface. ## Two planes Most operations are **control plane**: they run on the Routing Server, take small requests, and answer quickly. A few are **data plane**, marked `x-plane: data`, and go straight to the machine holding your project — the only practical way to move multi-gigabyte files or hold a connection open for half an hour. Data-plane operations use a different host and a different credential. Create a session on a project and it returns both: a `dataPlane.url` to send to and a short-lived `dataPlane.token` (`dav_gr_…`, a *grant*) to send with. A grant reaches exactly one project, carries no more permission than the key that minted it, expires in minutes, and dies when its session closes. It is not interchangeable with an API key in either direction. The data-plane host never names a specific machine, so a project that moves between machines mid-session stays reachable at the same URL. servers: - url: https://davinci-app.com description: Production (control plane) - url: https://davinci-app.com/data description: >- Production (data plane). Serves the operations marked `x-plane: data`, using a session's grant rather than an API key. tags: - name: Projects description: Create, inspect, open, close, and delete projects, and manage their attached files. - name: Content description: | Read and write the objects a project is made of. These reach the running project rather than storage, so they see uncommitted work — and so they open the project if it is not already open. - name: Branches description: | Branches, commits, and the history of a single object. A commit captures the running project's state, so these operations need the branch loaded, which they arrange for the caller. - name: Sessions description: | A session opens a project, holds it open, and issues the grant that reaches the data plane. It is the programmatic equivalent of having a project open in a browser tab: while it lives, the project stays loaded. It is also where the agent lives. Send it a prompt, read its status from the session, read the transcript back, and stop a run that is going the wrong way. - name: AgentModels description: | Chat models available to your account. The returned keys are the values accepted by the session message API; availability follows your subscription, tenant, and any profile assigned to your account. - name: Tools description: | Invoke one of the agent's tools yourself, without the agent. Useful when you already know the operation you want and do not need a model to choose it — and when you want a deterministic result rather than an interpreted one. A tool is still held to the permissions of the credential invoking it, so a key cannot reach through a tool to something its scopes exclude. - name: Files description: | Data-plane file transfer. These reach your project's machine directly using a session's grant, which is what allows request bodies far larger than the control plane accepts. - name: Usage description: | What your models cost, broken down by model, project, session, or day. These read the usage ledger, which records one event per completed provider call — not your balances and limits, which are `/api/v2/users/me/accounting`. Usage is reported on an interval rather than per call, so a run that is still going may not be fully counted yet. Every response carries `asOf`, the moment the newest counted event was recorded, so you can see how current a total is instead of guessing. This is separate from `projects:read` on purpose: a key that reads your project data is not thereby allowed to see what you spend. - name: Evaluations description: | Lifecycle for the ephemeral target sandbox an evaluation runs against. Creation is available only to a `purpose=automation` grant issued to a running Code execution, so a sandbox always belongs to code rather than to a person's key. It returns a second, `purpose=evaluation` grant bound to the new sandbox; it never upgrades or replaces the source credential. - name: Tests description: | Asynchronously run an authored Test. The Test executes its linked Code object and applies its native evaluation criteria to derive the verdict. This is one way to start Code, not a prerequisite for anything the Code can do: the same function called directly holds the same authority. - name: Organizations description: Discover organizations available as containers for team planning. - name: Cards description: | Project-scoped agile cards, their index hierarchy, comments, tags, assignees, card dependencies, and design-object references. Project access is checked on every call; an inaccessible project is reported as not found. - name: Teams description: | Organization-scoped team boards, linked projects, workflow columns, sprints, analytics, and card placements. Team visibility is privacy preserving: inaccessible organizations, private teams, and cross-organization ids are reported as not found rather than revealing that they exist. security: - ApiKeyBearer: [] paths: /api/v2/agent/models: get: operationId: listAgentModels tags: [AgentModels] summary: List available agent models description: | Returns the chat models available through the calling account's effective LLM profile. Pass a model's `key` as `model` when sending an agent message, and use its `options` definitions to build `modelOptions`. The list can differ between accounts because subscription tier, tenant policy, and an account-specific profile can all affect it. Omitting `model` from a message uses `defaultModel`. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/agent/agent.routes.js x-required-scopes: [agent:message] x-sdk-methods: typescript: client.agentModels.list python: client.agent_models.list x-codeSamples: - lang: typescript label: TypeScript SDK source: | const available = await client.agentModels.list(); console.log('Default:', available.defaultModel); for (const model of available.models) { console.log(model.key, model.name); console.log(model.options); } - lang: python label: Python SDK source: | available = client.agent_models.list() print("Default:", available.default_model) for model in available.models: print(model.key, model.name) print(model.options) responses: '200': description: Models available to the calling account. content: application/json: schema: $ref: '#/components/schemas/ListAgentModelsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '409': description: The account has no usable published LLM profile. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects: get: operationId: listProjects tags: [Projects] summary: List accessible projects description: | Returns the caller's projects split into `owned` and `shared`. Each entry carries an `inUse` flag and the most recently active running branch associated with the caller. Clients should use `main` when `activeBranch` is null. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.projects.list python: client.projects.list x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { owned, shared } = await client.projects.list(); for (const project of [...owned, ...shared]) { console.log(project.id, project.name, project.inUse); } - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.projects.list() for project in [*result.owned, *result.shared]: print(project.id, project.name, project.in_use) responses: '200': description: The caller's owned and shared projects. content: application/json: schema: $ref: '#/components/schemas/ListProjectsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createProject tags: [Projects] summary: Create a project description: | Creates a project owned by the caller, or by `orgId` when supplied. Either `name` or `initialPrompt` is required. When `autoName` is set with an `initialPrompt`, the name is derived from the prompt. Send an `Idempotency-Key` header to make a retry safe. Creating a project writes a repository and an initial commit, and a duplicate is not reclaimed, so a request that times out after the server completed it would otherwise leave you choosing between a leaked project and a lost one. A repeat of the same key returns the project the first call created, with the same `201`. security: - ApiKeyBearer: [] parameters: - $ref: '#/components/parameters/IdempotencyKey' x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:manage] x-sdk-methods: typescript: client.projects.create python: client.projects.create x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const project = await client.projects.create({ name: 'Spacecraft' }); console.log(project.id); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: project = client.projects.create(name="Spacecraft") print(project.id) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateProjectRequest' responses: '201': description: Project created. content: application/json: schema: $ref: '#/components/schemas/CreateProjectResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': description: | Scope missing, project limit reached (`PROJECT_LIMIT_REACHED`), or no permission to create in the requested organization. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': $ref: '#/components/responses/NotFound' '409': description: | The Idempotency-Key is currently initializing a project, was reused with different create settings, or points to a result that is no longer available. Error code is `PROJECT_CREATE_IN_PROGRESS`, `IDEMPOTENCY_KEY_REUSED`, or `IDEMPOTENCY_RESULT_UNAVAILABLE`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: getProject tags: [Projects] summary: Get project metadata description: | Returns the project's stored metadata, including its owner, visibility, version, storage footprint, and effective collaborators. Use the permissions endpoint when you need to know what this credential may do with the project; those are reported separately because they are derived per credential rather than stored on the project. x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.projects.get python: client.projects.get x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { metadata } = await client.projects.get(projectId); console.log(metadata.name, metadata.visibility); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.projects.get(project_id) print(result.metadata.name, result.metadata.visibility) responses: '200': description: Project metadata. content: application/json: schema: $ref: '#/components/schemas/GetProjectResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' patch: operationId: updateProject tags: [Projects] summary: Update project metadata description: Updates any subset of name, description, visibility, readme, tags, or units. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:manage] x-sdk-methods: typescript: client.projects.update python: client.projects.update x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { metadata } = await client.projects.update(projectId, { description: 'Launch vehicle upper stage', }); console.log(metadata.description); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.projects.update( project_id, description="Launch vehicle upper stage" ) print(result.metadata.description) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateProjectRequest' responses: '200': description: Updated project metadata. content: application/json: schema: $ref: '#/components/schemas/UpdateProjectResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteProject tags: [Projects] summary: Delete a project description: | Soft-deletes the project. Storage is released from the owner's balance and the project becomes invisible to normal reads; a system administrator can restore it for a retention window. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:manage] x-sdk-methods: typescript: client.projects.delete python: client.projects.delete x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.projects.delete(projectId); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: client.projects.delete(project_id) responses: '204': description: Project deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/open: parameters: - $ref: '#/components/parameters/ProjectId' post: operationId: openProject tags: [Projects] summary: Open a project description: | Loads the project onto a Design Engine replica, or returns the already-running instance. `alreadyLoaded` distinguishes the two. API-key callers receive lifecycle confirmation only. The `url` and `serverToken` fields that a browser receives are omitted, because `serverToken` is minted per project rather than per user and would let its holder act as any collaborator. Programmatic access to live project data will use short-lived project-scoped grants instead. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.projects.open python: client.projects.open x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const opened = await client.projects.open(projectId, { branch: 'main' }); console.log(opened.branchName, opened.alreadyLoaded); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: opened = client.projects.open(project_id, branch="main") print(opened.branch_name, opened.already_loaded) requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/OpenProjectRequest' responses: '200': description: Project is loaded and ready. content: application/json: schema: $ref: '#/components/schemas/OpenProjectResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': description: | No Design Engine replica could take the project. Common codes are `PROJECT_SERVER_UNAVAILABLE` and `SERVICE_UNAVAILABLE`. Safe to retry. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /api/v2/projects/{projectId}/close: parameters: - $ref: '#/components/parameters/ProjectId' post: operationId: closeProject tags: [Projects] summary: Close a project description: | Saves and unloads the running Design Engine instance. Closing a project that is not running succeeds without effect, so this is safe to call unconditionally in cleanup paths. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.projects.close python: client.projects.close x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.projects.close(projectId); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: client.projects.close(project_id) responses: '200': description: Project closed. content: application/json: schema: $ref: '#/components/schemas/SuccessResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/branches: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: listProjectBranches tags: [Projects] summary: List project branches description: Returns the authoritative git branches for the project from storage. x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.projects.listBranches python: client.projects.list_branches x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { branches } = await client.projects.listBranches(projectId); console.log(branches.map((branch) => branch.name)); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.projects.list_branches(project_id) print([branch.name for branch in result.branches]) responses: '200': description: Project branches. content: application/json: schema: $ref: '#/components/schemas/ListBranchesResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createBranch tags: [Branches] summary: Create a branch description: | Branches from another branch at its latest commit, copying its committed content. Uncommitted work on the source is not carried over. Branch names are sanitized, so the created name is not always the requested one. `branch.name` is what was created and `sanitized` says whether it differs. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/projectGit.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.branches.create python: client.branches.create x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { branch } = await client.branches.create(projectId, { name: 'thermal-study' }); console.log(branch.name); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.branches.create(project_id, name="thermal-study") print(result.branch.name) parameters: - $ref: '#/components/parameters/Branch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateBranchRequest' responses: '201': description: Branch created. content: application/json: schema: $ref: '#/components/schemas/CreateBranchResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | Project not found, or the source branch does not exist. Error code is `SOURCE_BRANCH_NOT_FOUND` for the latter. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: | A branch of that name already exists (`BRANCH_ALREADY_EXISTS`), or the project is no longer running (`PROJECT_NOT_RUNNING`). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '502': $ref: '#/components/responses/GitFailed' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/branches/{branch}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BranchPath' delete: operationId: deleteBranch tags: [Branches] summary: Delete a branch description: | Deletes a branch and the commits only it holds. There is no undo, which is why this asks for `projects:manage` where creating a branch asks for `projects:write`. Refused with `BRANCH_IN_USE` while anyone is connected to the branch. Pass `force=true` to disconnect them instead; their in-memory work is saved to the branch first, and then goes with it. `main` cannot be deleted. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/projectGit.routes.js x-required-scopes: [projects:manage] x-sdk-methods: typescript: client.branches.delete python: client.branches.delete x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.branches.delete(projectId, 'thermal-study'); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: client.branches.delete(project_id, "thermal-study") parameters: - name: force in: query required: false schema: type: boolean default: false description: Disconnect anyone using the branch instead of refusing. responses: '200': description: Branch deleted. content: application/json: schema: $ref: '#/components/schemas/DeleteBranchResponse' '400': description: | The branch cannot be deleted as asked. Error code is `CANNOT_DELETE_MAIN`, `BRANCH_IN_USE`, `BRANCH_NOT_FOUND`, or `UNMERGED_COMMITS`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '502': $ref: '#/components/responses/GitFailed' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/branches/{branch}/commits: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BranchPath' post: operationId: createCommit tags: [Branches] summary: Commit a branch description: | Commits everything uncommitted on the branch. There is nothing to stage — the working state is the live project, not a checkout, so a commit is all of it or nothing. Committing requires the branch to be loaded, which this does on the caller's behalf. A commit of an untouched branch still produces a revision. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/projectGit.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.branches.commit python: client.branches.commit x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { commit } = await client.branches.commit(projectId, 'main', { message: 'Seed requirements', }); console.log(commit.hash); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.branches.commit(project_id, "main", message="Seed requirements") print(result.commit.hash) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommitRequest' responses: '201': description: Commit created. content: application/json: schema: $ref: '#/components/schemas/CommitResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '502': $ref: '#/components/responses/GitFailed' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/branches/{branch}/changes: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BranchPath' get: operationId: getBranchChanges tags: [Branches] summary: Read uncommitted changes description: | Returns which objects on the branch differ from its last commit, as three lists of ids plus enough metadata to name the deleted ones. Deleted objects come with their name and type because they can no longer be read from the project. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/projectGit.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.branches.getChanges python: client.branches.get_changes x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const changes = await client.branches.getChanges(projectId, 'main'); console.log(changes.hasChanges, changes.added.length); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: changes = client.branches.get_changes(project_id, "main") print(changes.has_changes, len(changes.added)) responses: '200': description: Uncommitted changes. content: application/json: schema: $ref: '#/components/schemas/ChangesResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '502': $ref: '#/components/responses/GitFailed' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/packages: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: listProjectPackages tags: [Projects] summary: List public packages description: | Returns the project's public packages, which are the units another project can include by reference. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.projects.listPackages python: client.projects.list_packages x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { packages } = await client.projects.listPackages(projectId, { branch: 'main' }); console.log(packages.length); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.projects.list_packages(project_id, branch="main") print(len(result.packages)) parameters: - $ref: '#/components/parameters/Branch' responses: '200': description: Public packages. content: application/json: schema: $ref: '#/components/schemas/ListPackagesResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/tree: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: getProjectTree tags: [Content] summary: Read the object tree description: | Returns every object in the project as a flat list, with parentage expressed by `parent` and `childrenCount`. This reads the running project, so it opens it if it is not already open, and it shows uncommitted state — which is the state a caller that just wrote something is asking about. The storage-backed reads are cheaper but only show the last save. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.content.getTree python: client.content.get_tree x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { tree } = await client.content.getTree(projectId); for (const node of tree) { console.log(node.type, node.name); } - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.content.get_tree(project_id) for node in result.tree: print(node.type, node.name) parameters: - $ref: '#/components/parameters/Branch' responses: '200': description: The project's objects. content: application/json: schema: $ref: '#/components/schemas/ProjectTree' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/objects: parameters: - $ref: '#/components/parameters/ProjectId' post: operationId: addProjectObjects tags: [Content] summary: Add objects description: | Adds objects to the running project, opening it if needed. The write goes through the same path an interactive client uses, so parentage, layout, and the broadcast to anyone else in the project all happen as normal. The objects are in memory once this returns; they are in git only after a commit. A response reporting fewer objects than were sent does not happen — the request either applies in full or fails. Every object is checked against the schema for its `type` before anything is written, so one bad object fails the whole request and the project is left untouched. Any type the model defines can be written here; the 400 names what was wrong with each object it refused. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.content.addObjects python: client.content.add_objects x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { addedCount } = await client.content.addObjects(projectId, { objects: { [crypto.randomUUID()]: { type: 'requirement', name: 'Dry mass under 500 kg' }, }, }); console.log(addedCount); - lang: python label: Python SDK source: | import os import uuid from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.content.add_objects( project_id, objects={str(uuid.uuid4()): {"type": "requirement", "name": "Dry mass under 500 kg"}}, ) print(result.added_count) parameters: - $ref: '#/components/parameters/Branch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddObjectsRequest' responses: '201': description: Objects added. content: application/json: schema: $ref: '#/components/schemas/AddObjectsResponse' '400': description: | Nothing was written. `INVALID_OBJECTS` means the `objects` map itself was missing, empty, or not a map. `INVALID_OBJECT` means at least one object failed its schema: `details.objects` maps each refused id to what is wrong with it, and `details.validTypes` lists every writable type when a `type` was the problem. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '502': description: | The project accepted the request but applied none of it. Error code is `OBJECTS_NOT_APPLIED`. Nothing was written; the request can be retried. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/objects/{objectId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/ObjectId' get: operationId: getProjectObject tags: [Content] summary: Read an object description: | Returns one object with its computed values resolved, from the running project. Fields vary by object type. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.content.getObject python: client.content.get_object x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { object } = await client.content.getObject(projectId, objectId); console.log(object.name); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.content.get_object(project_id, object_id) print(result.object) parameters: - $ref: '#/components/parameters/Branch' responses: '200': description: The object. content: application/json: schema: $ref: '#/components/schemas/GetObjectResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | Project or object not found. Error code is `OBJECT_NOT_FOUND` when the project was readable but the object was not in it. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ProjectNotReady' delete: operationId: deleteProjectObject tags: [Content] summary: Delete an object description: | Deletes an object from the running project, together with its descendants. Parent links, relationships, indexes, and other model references are cleaned through the same update path used by the editor. The change is uncommitted when this returns. Call `createCommit` to save it in git. Deleting a reference object does not delete its stored file bytes, because file storage is shared across branches. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.content.deleteObject python: client.content.delete_object x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const result = await client.content.deleteObject(projectId, objectId); console.log(result.deletedObjectIds); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.content.delete_object(project_id, object_id) print(result.deleted_object_ids) parameters: - $ref: '#/components/parameters/Branch' responses: '200': description: The object and its descendants were deleted. content: application/json: schema: $ref: '#/components/schemas/DeleteObjectResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: Project or object not found. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: The object is protected, locked, or cannot be deleted independently. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/objects/{objectId}/history: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/ObjectId' get: operationId: getObjectHistory tags: [Branches] summary: Read an object's commit history description: | Returns the commits on a branch that changed one object, newest first, each with the object's state at that commit and the fields that changed. Commits that did not touch the object are omitted, so this is not a slice of the project history — it is the object's own. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/projectGit.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.branches.getObjectHistory python: client.branches.get_object_history x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { history } = await client.branches.getObjectHistory(projectId, objectId); for (const entry of history) { console.log(entry.commit.shortHash, entry.changeType); } - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.branches.get_object_history(project_id, object_id) for entry in result.history: print(entry.commit.short_hash, entry.change_type) parameters: - $ref: '#/components/parameters/Branch' - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 200 default: 50 responses: '200': description: The object's history on this branch. content: application/json: schema: $ref: '#/components/schemas/ObjectHistoryResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ProjectNotRunning' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '502': $ref: '#/components/responses/GitFailed' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/projects/{projectId}/files: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: listProjectFiles tags: [Projects] summary: List attached files description: | Returns the files attached to a branch from committed branch HEAD. Each reference is joined to its `assets.primary` descriptor when present, so the listed filename and size describe the immutable SHA-addressed blob. Older snapshots without asset metadata retain the legacy files-prefix lookup. Read from the branch's saved snapshot rather than from the running project, so it works whether or not the project is open — and so a file attached since the last save is not listed yet. A reference whose bytes are missing from storage is listed with a null `size`, because the object exists and omitting it would hide a half-finished upload. The reverse does not hold: stored bytes with no reference on this branch are not listed, since storage is shared across branches and one branch cannot tell an orphan from another branch's file. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.projects.listFiles python: client.projects.list_files x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const { files } = await client.projects.listFiles(projectId); for (const file of files) { console.log(file.filename, file.size ?? 'missing'); } - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: result = client.projects.list_files(project_id) for file in result.files: print(file.filename, file.size) parameters: - $ref: '#/components/parameters/Branch' responses: '200': description: Files attached to the branch. content: application/json: schema: $ref: '#/components/schemas/ListFilesResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/files/{fileId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FileId' delete: operationId: deleteProjectFile tags: [Projects] summary: Delete an attached file description: Removes a file and all of its stored variants from the project. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.projects.deleteFile python: client.projects.delete_file x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.projects.deleteFile(projectId, fileId); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: client.projects.delete_file(project_id, file_id) responses: '204': description: File deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: Project or file not found. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/files/{fileId}/content: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FileId' get: operationId: downloadProjectFile tags: [Projects] summary: Download an attached file description: | Streams the bytes of a referenced file. `fileId` may be a reference object id or a stored filename. An authenticated caller receives current working bytes when this exact branch is already active on a Design Engine. This request never starts a project; if no live instance is available it falls back to committed branch HEAD. Anonymous access to a public project always reads committed branch HEAD and never observes working state. Committed snapshots use the immutable `assets.primary.sha256` blob, with a legacy files-prefix fallback for older snapshots. x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.projects.downloadFile python: client.projects.download_file x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const bytes = await client.projects.downloadFile(projectId, fileId); console.log(bytes.byteLength); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: data = client.projects.download_file(project_id, file_id) print(len(data)) parameters: - $ref: '#/components/parameters/Branch' responses: '200': description: File bytes. headers: Content-Type: schema: type: string Content-Disposition: schema: type: string content: application/octet-stream: schema: type: string format: binary '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: File not found. Error code is `REFERENCED_FILE_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/sessions: parameters: - $ref: '#/components/parameters/ProjectId' post: operationId: createSession tags: [Sessions] summary: Open a session and mint a data-plane grant description: | Loads the project, holds it open, and returns the credential for reaching it directly. A project unloads shortly after nothing is connected to it, so a session is what keeps it resident between your requests. Poll the session (`getSession`) to both refresh the grant and signal that you are still working. The grant can never exceed the key that minted it. Omit `scopes` to inherit the key's own scopes; supply them to narrow the grant further, which is worth doing when one job needs less than the key can do. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [sessions:manage] x-sdk-methods: typescript: client.sessions.create python: client.sessions.create x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const session = await client.sessions.create(projectId); console.log(session.sessionId, session.dataPlane.url); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: session = client.sessions.create(project_id) print(session.session_id, session.data_plane.url) requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CreateSessionRequest' responses: '201': description: The session, with the grant needed to reach the data plane. content: application/json: schema: $ref: '#/components/schemas/Session' '400': description: | Invalid request. Error code is `INVALID_SCOPES` for an unknown scope name or `INVALID_TTL` for a non-positive `ttlSeconds`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': description: | The caller lacks `project:connect` on this project, or asked for scopes the key does not hold (`INSUFFICIENT_SCOPES`). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '503': description: | The project could not be opened or its machine is unavailable. Error code is `PROJECT_NOT_READY`, `SERVER_NOT_AVAILABLE`, or `GRANT_PUSH_FAILED`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/sessions/{sessionId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/SessionId' get: operationId: getSession tags: [Sessions] summary: Read a session, refresh its grant, and check the agent description: | Returns the session with a **new** grant and revokes the previous one, so a leaked grant stops working at the next poll rather than at its expiry. This is also the keepalive, for both clocks that matter: the grant's expiry and the machine's idle timer. Call it well before `dataPlane.expiresAt` — the SDKs do this for you. `agent.status` is how you follow a run started with `sendAgentMessage`. It is reported here rather than on a route of its own precisely so that one poll keeps the session alive and tells you where the run is. `completed`, `failed`, and `paused` are terminal; `paused` is what a `stopAgent` produces. `unknown` means the machine could not be reached for this field alone — the grant in the same response is still good, so retry rather than recreating the session. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.sessions.get python: client.sessions.get x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const refreshed = await client.sessions.get(projectId, sessionId); console.log(refreshed.dataPlane.expiresAt, refreshed.agent?.status); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: refreshed = client.sessions.get(project_id, session_id) print(refreshed.data_plane.expires_at, refreshed.agent.status) responses: '200': description: The session, with a freshly minted grant. content: application/json: schema: $ref: '#/components/schemas/Session' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, or it belongs to another user. Error code is `SESSION_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: | The project this session opened is no longer running. Error code is `PROJECT_NOT_RUNNING`; create a new session. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteSession tags: [Sessions] summary: Close a session description: | Releases the project and revokes every grant the session issued. Grants stop working immediately rather than at expiry, which is the point of closing a session rather than letting it lapse. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/project/project.routes.js x-required-scopes: [sessions:manage] x-sdk-methods: typescript: client.sessions.delete python: client.sessions.delete x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.sessions.delete(projectId, sessionId); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: client.sessions.delete(project_id, session_id) responses: '200': description: The session was closed. content: application/json: schema: $ref: '#/components/schemas/DeleteSessionResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, or it belongs to another user. Error code is `SESSION_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/sessions/{sessionId}/messages: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/SessionId' post: operationId: sendAgentMessage tags: [Sessions] summary: Send a prompt to the session's agent description: | Gives the agent something to do. Starts a run if none is going, and adds a turn to the conversation if one is. This returns as soon as the agent has accepted the prompt, not when it has finished — a run takes as long as the work takes. Follow it with `getSession` and read `agent.status`, or let the SDK's `waitUntilDone` do that for you. Acceptance is not the same as success. A `202` means the agent took the prompt; a `409` means it refused, which happens when the run it belonged to has ended. Recreate the session in that case rather than retrying the message. The agent can change anything in the project and is charged for AI usage doing it, which is why this needs the `agent:message` scope rather than a project write. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/agent/agent.routes.js x-required-scopes: [agent:message] x-sdk-methods: typescript: session.sendMessage python: session.send_message x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.sessions.with(projectId, async (session) => { await session.sendMessage('Add a 10mm M3 standoff under each corner of the base plate'); const final = await session.waitUntilDone(); console.log(final.status); }); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: with client.sessions.create(project_id) as session: session.send_message( "Add a 10mm M3 standoff under each corner of the base plate" ) final = session.wait_until_done() print(final.status) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SendAgentMessageRequest' responses: '202': description: The agent accepted the prompt. The run is now in progress. content: application/json: schema: $ref: '#/components/schemas/SendAgentMessageResponse' '400': description: | Invalid request. Error code is `MISSING_MESSAGE`, `MESSAGE_TOO_LARGE`, `INVALID_MESSAGE_ID`, `INVALID_CONTEXT`, `INVALID_PERSONA`, `UNKNOWN_PERSONA`, `INVALID_MODEL`, `UNKNOWN_MODEL`, `INVALID_MODEL_OPTIONS`, `INVALID_WEB_SEARCH`, `LLM_OPTION_UNKNOWN`, or `LLM_OPTION_VALUE_UNAVAILABLE`. `UNKNOWN_PERSONA` names a persona the project does not define, and carries `details.definedPersonas` — the ids that would have worked. The message is refused rather than run under a default persona you did not ask for. `UNKNOWN_MODEL` names a well-formed model key outside the calling account's effective profile and carries `details.availableModels`. An invalid model option identifies its model and option key in `details.model` and `details.option`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, it belongs to another user, or it belongs to a different project than the one in the path. Error code is `SESSION_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: | The agent refused the message (`MESSAGE_REFUSED`), or the project the session opened is no longer running (`PROJECT_NOT_RUNNING`). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' get: operationId: listAgentMessages tags: [Sessions] summary: Read the session's conversation description: | The transcript: your prompts, the agent's replies and reasoning, and every tool it used with the result. `source` tells you where the answer came from. `live` is the running agent's own copy and is current. `persisted` is the saved copy, which is written when a run ends — so it is complete for a finished run but behind for a running one. `none` means there is no conversation yet. Entries are ordered oldest to newest and `limit` takes the most recent, which is usually what you want after a run. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/agent/agent.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: session.messages python: session.messages x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const session = await client.sessions.get(projectId, sessionId); const transcript = await session.messages({ limit: 20 }); for (const entry of transcript.messages) { console.log(entry.role, entry.kind, entry.text); } - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: session = client.sessions.resume(project_id, session_id) transcript = session.messages(limit=20) for entry in transcript.messages: print(entry.role, entry.kind, entry.text) parameters: - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 500 default: 100 description: Most recent entries to return. responses: '200': description: The conversation. content: application/json: schema: $ref: '#/components/schemas/AgentTranscript' '400': description: '`limit` is out of range. Error code is `INVALID_LIMIT`.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, it belongs to another user, or it belongs to a different project than the one in the path. Error code is `SESSION_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/sessions/{sessionId}/stop: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/SessionId' post: operationId: stopAgent tags: [Sessions] summary: Stop the agent without closing the session description: | Halts the current run. The session survives, the project stays open, and the conversation so far is kept — so you can send a new prompt afterwards without starting over. Use `deleteSession` when you actually want to finish. Stopping when nothing is running is not an error; `stopped` is `false` and the status is whatever it already was. That makes this safe to call defensively, for instance when abandoning a run you may or may not have started. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/agent/agent.routes.js x-required-scopes: [sessions:manage] x-sdk-methods: typescript: session.stop python: session.stop x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const session = await client.sessions.get(projectId, sessionId); const result = await session.stop(); console.log(result.stopped, result.status); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: session = client.sessions.resume(project_id, session_id) result = session.stop() print(result.stopped, result.status) responses: '200': description: The run was halted, or there was none to halt. content: application/json: schema: $ref: '#/components/schemas/StopAgentResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, it belongs to another user, or it belongs to a different project than the one in the path. Error code is `SESSION_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: | The project this session opened is no longer running. Error code is `PROJECT_NOT_RUNNING`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/sessions/{sessionId}/tools/invoke: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/SessionId' post: operationId: invokeTool tags: [Tools] summary: Invoke one of the agent's tools directly description: | Runs a single tool and returns its result, with no model in the loop. Faster and deterministic where the agent is neither, and it incurs no LLM charges. This needs a session because a tool belongs to one: the tools available are the ones the session's project has open, and the tool acts on that project's live state. A tool that refuses answers `422` with the tool's own message. Permission refusals are deliberately indistinguishable from "no such tool" — a key cannot use the error to discover what it is not allowed to do. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/agent/agent.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: session.invokeTool python: session.invoke_tool x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.sessions.with(projectId, async (session) => { const result = await session.invokeTool({ toolbox: 'Core', tool: 'ReadObject', params: { objectId }, }); console.log(result.content.text); }); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: with client.sessions.create(project_id) as session: result = session.invoke_tool( toolbox="Core", tool="ReadObject", params={"objectId": object_id}, ) print(result.content.text) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/InvokeToolRequest' responses: '200': description: The tool ran and returned a result. content: application/json: schema: $ref: '#/components/schemas/InvokeToolResponse' '400': description: | Invalid request. Error code is `MISSING_TOOL_TARGET`, `INVALID_TOOL_TARGET`, or `INVALID_PARAMS`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, it belongs to another user, it belongs to a different project than the one in the path (`SESSION_NOT_FOUND`), or no such toolbox for this session. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: | The project this session opened is no longer running. Error code is `PROJECT_NOT_RUNNING`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '422': description: | The tool ran and refused: bad arguments, a precondition it needs, or a permission your credential does not hold. Error code is `TOOL_ERROR` and the message is the tool's own. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/usage: get: operationId: getUsage tags: [Usage] summary: What you spent description: | Dollars and tokens charged to your account, optionally narrowed by project, session, or time, and optionally broken down by model, project, session, or day. This reports your own usage. A project you share with collaborators returns what *you* spent on it, not the project's total — what someone else spends is their financial data, not the project's. Reads are eventually consistent with a live run: the engine reports usage on an interval, so check `asOf` before treating a total as final. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/billing/reporting/accountingReport.routes.js x-required-scopes: [usage:read] x-sdk-methods: typescript: client.usage.get python: client.usage.get parameters: - name: projectId in: query required: false description: Narrow to one project. Accepts the bare id or `{projectId}--{branch}`. schema: type: string - name: sessionId in: query required: false description: Narrow to one session. schema: type: string - $ref: '#/components/parameters/UsageFrom' - $ref: '#/components/parameters/UsageTo' - $ref: '#/components/parameters/UsageGroupBy' x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const usage = await client.usage.get({ groupBy: 'model' }); for (const row of usage.groups ?? []) { console.log(row.model, row.amountUsd); } - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: usage = client.usage.get(group_by="model") for row in usage.groups or []: print(row.model, row.amount_usd) responses: '200': description: Usage totals for the scope, and the breakdown if one was asked for. content: application/json: schema: $ref: '#/components/schemas/UsageResponse' '400': description: | Invalid request. Error code is `INVALID_GROUP_BY` or `INVALID_RANGE`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/usage: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: getProjectUsage tags: [Usage] summary: What you spent on one project description: | The same reading as `getUsage`, scoped to one project and authorized against it — you must be able to read the project as well as hold `usage:read`. Usage is recorded against the bare project id, so this covers every branch of the project rather than only the one you name. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/billing/reporting/accountingReport.routes.js x-required-scopes: [usage:read, projects:read] x-sdk-methods: typescript: client.usage.forProject python: client.usage.for_project parameters: - $ref: '#/components/parameters/UsageFrom' - $ref: '#/components/parameters/UsageTo' - $ref: '#/components/parameters/UsageGroupBy' x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const usage = await client.usage.forProject(projectId, { groupBy: 'day' }); console.log(usage.totals.amountUsd, usage.asOf); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: usage = client.usage.for_project(project_id, group_by="day") print(usage.totals.amount_usd, usage.as_of) responses: '200': description: Usage totals for the project. content: application/json: schema: $ref: '#/components/schemas/UsageResponse' '400': description: | Invalid request. Error code is `INVALID_GROUP_BY` or `INVALID_RANGE`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/sessions/{sessionId}/usage: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/SessionId' get: operationId: getSessionUsage tags: [Usage] summary: What one session spent description: | What a single session's agent run cost. This is the granularity to use when you want to know the price of a specific piece of work rather than a month of it. A run still in progress will under-report until its last interval is flushed, so read `asOf` — or read this after `waitUntilDone` returns. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/billing/reporting/accountingReport.routes.js x-required-scopes: [usage:read, projects:read] x-sdk-methods: typescript: session.usage python: session.usage parameters: - $ref: '#/components/parameters/UsageFrom' - $ref: '#/components/parameters/UsageTo' - $ref: '#/components/parameters/UsageGroupBy' x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); await client.sessions.with(projectId, async (session) => { await session.sendMessage('Add a mounting bracket'); await session.waitUntilDone(); const usage = await session.usage(); console.log(`That run cost $${usage.totals.amountUsd}`); }); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: with client.sessions.create(project_id) as session: session.send_message("Add a mounting bracket") session.wait_until_done() usage = session.usage() print(f"That run cost ${usage.totals.amount_usd}") responses: '200': description: Usage totals for the session. content: application/json: schema: $ref: '#/components/schemas/UsageResponse' '400': description: | Invalid request. Error code is `INVALID_GROUP_BY` or `INVALID_RANGE`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: | No such session, it belongs to another user, or it belongs to a different project than the one in the path. Error code is `SESSION_NOT_FOUND`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v1/file/upload/{ownerId}/{userId}/{projectId}/{connectionId}/{parentId}: parameters: - $ref: '#/components/parameters/DataPlaneOwnerId' - $ref: '#/components/parameters/DataPlaneUserId' - $ref: '#/components/parameters/DataPlaneProjectId' - $ref: '#/components/parameters/ConnectionId' - $ref: '#/components/parameters/ParentId' post: operationId: uploadFile tags: [Files] summary: Upload a file to a project x-plane: data description: | Sends a file to the machine holding your project and attaches it under `parentId` in the parts tree. Send this to `dataPlane.url`, not to the control-plane host, with `Authorization: Bearer {dataPlane.token}`. Supply the session's own `dataPlane.connectionId` as `connectionId`; the upload is applied through the session's live connection, so any other value is rejected. Bodies up to 2 GB are accepted and streamed rather than buffered. security: - GrantBearer: [] x-routing-server-source: DesignEngine/src/api/routes/fileRoutes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: session.upload python: session.upload x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { readFile } from 'node:fs/promises'; import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const session = await client.sessions.create(projectId); const result = await session.upload({ file: await readFile('housing.step'), filename: 'housing.step', parentId: rootId, }); console.log(result.fileId); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: session = client.sessions.create(project_id) with open("housing.step", "rb") as handle: result = session.upload(handle, filename="housing.step", parent_id=root_id) print(result.file_id) requestBody: required: true content: multipart/form-data: schema: $ref: '#/components/schemas/UploadFileRequest' responses: '200': description: The file was stored and attached. content: application/json: schema: $ref: '#/components/schemas/UploadFileResponse' '401': $ref: '#/components/responses/GrantRejected' '403': description: The grant does not carry `documents:write` on this project. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': $ref: '#/components/responses/ProjectMoved' '413': description: The file exceeds the maximum upload size. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v1/file/download/{ownerId}/{projectId}/{fileName}: parameters: - $ref: '#/components/parameters/DataPlaneOwnerId' - $ref: '#/components/parameters/DataPlaneProjectId' - $ref: '#/components/parameters/FileName' get: operationId: downloadFileDirect tags: [Files] summary: Download a file from a project x-plane: data description: | Streams a file from the machine holding your project. Send this to `dataPlane.url` with `Authorization: Bearer {dataPlane.token}`. Prefer this over the control-plane `downloadProjectFile` for large files: the bytes travel directly rather than through the API server, with a 30-minute window rather than 15. A file belonging to a different project is served only when your project has an active include referencing it — the same rule the editor follows. security: - GrantBearer: [] x-routing-server-source: DesignEngine/src/api/routes/fileRoutes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: session.download python: session.download x-codeSamples: - lang: typescript label: TypeScript SDK source: | import { DavinciClient } from '@celedon/davinci-sdk'; const client = new DavinciClient({ apiKey: process.env.DAVINCI_API_KEY!, }); const session = await client.sessions.create(projectId); const bytes = await session.download('housing.step'); console.log(bytes.byteLength); - lang: python label: Python SDK source: | import os from davinci_sdk import DavinciClient with DavinciClient(api_key=os.environ["DAVINCI_API_KEY"]) as client: session = client.sessions.create(project_id) data = session.download("housing.step") print(len(data)) responses: '200': description: File bytes. headers: Content-Type: schema: type: string Content-Disposition: schema: type: string content: application/octet-stream: schema: type: string format: binary '401': $ref: '#/components/responses/GrantRejected' '403': description: | The grant does not carry `documents:read`, or the file belongs to another project with no active include referencing it. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: No such file. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': $ref: '#/components/responses/ProjectMoved' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/evaluation-runs: post: operationId: createEvaluationRun tags: [Evaluations] summary: Create an ephemeral evaluation sandbox description: | Creates a separate ephemeral project to evaluate against. The caller must hold the `purpose=automation` grant issued to a running Code execution, which is what binds the sandbox to code rather than to a person's key. The source project and execution are taken from the grant rather than accepted from the body. The response contains sandbox metadata and a second, `purpose=evaluation` grant/data-plane block bound to that sandbox. This target grant can seed and inspect the sandbox and drive its agent, but cannot access another project, account resources, or git routes. security: - ExecutionGrantBearer: [] x-routing-server-source: RoutingServer/evaluationRun/evaluationRun.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.evaluations.create python: client.evaluations.create requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateEvaluationRunRequest' responses: '201': description: The target sandbox is ready and its grant has been attached. content: application/json: schema: $ref: '#/components/schemas/EvaluationRun' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/InfrastructureFailure' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ProjectNotReady' /api/v2/evaluation-runs/{runId}: parameters: - $ref: '#/components/parameters/RunId' get: operationId: getEvaluationRun tags: [Evaluations] summary: Get an evaluation sandbox run description: | Reads lifecycle, quality, evidence, and cleanup state. The Code execution's own grant or the user credential behind it may read the run. Tokens are returned only to the execution grant while the sandbox is live. security: - ExecutionGrantBearer: [] - ApiKeyBearer: [] x-routing-server-source: RoutingServer/evaluationRun/evaluationRun.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.evaluations.status python: client.evaluations.status responses: '200': description: Current evaluation-run state. content: application/json: schema: $ref: '#/components/schemas/EvaluationRun' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteEvaluationRun tags: [Evaluations] summary: Clean up an evaluation sandbox description: | Idempotently stops target work, revokes target grants, releases the sandbox pin, and deletes the ephemeral project. Cleanup state is retained as evidence; a cleanup error never hides the run's primary failure. security: - ExecutionGrantBearer: [] - ApiKeyBearer: [] x-routing-server-source: RoutingServer/evaluationRun/evaluationRun.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.evaluations.cancel python: client.evaluations.cancel responses: '200': description: Cleanup completed or had already completed. content: application/json: schema: $ref: '#/components/schemas/EvaluationRun' '202': description: Cleanup has been requested and is still running. content: application/json: schema: $ref: '#/components/schemas/EvaluationRun' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/tests/{testId}/runs: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/TestId' post: operationId: createTestRun tags: [Tests] summary: Start an authored Test asynchronously description: | Validates a runnable leaf Test and starts its Results Value expression. When that expression calls a Code object, the Code runs with the ordinary `purpose=automation` execution grant it would have received from any other caller. The route returns after scheduling; poll the run resource for evidence, observation, native verdict, or infrastructure failure. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/testRun/testRun.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.tests.run python: client.tests.run requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CreateTestRunRequest' responses: '202': description: Test run accepted. headers: Location: schema: type: string description: URL of the new Test-run resource. content: application/json: schema: $ref: '#/components/schemas/TestRun' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/InfrastructureFailure' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/tests/{testId}/runs/{runId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/TestId' - $ref: '#/components/parameters/RunId' get: operationId: getTestRun tags: [Tests] summary: Get Test-run status and evidence description: | Returns async lifecycle, structured evidence, numeric observation, native Test verdict, or an infrastructure failure for one authored Test run. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/testRun/testRun.routes.js x-required-scopes: [projects:read] x-sdk-methods: typescript: client.tests.status python: client.tests.status responses: '200': description: Current or terminal Test-run state. content: application/json: schema: $ref: '#/components/schemas/TestRun' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteTestRun tags: [Tests] summary: Cancel a Test run description: | Requests cancellation and evaluation-sandbox cleanup. The operation is idempotent. A run already completed remains completed; a run that can be interrupted moves through `cancelling` to `cancelled`. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/testRun/testRun.routes.js x-required-scopes: [projects:write] x-sdk-methods: typescript: client.tests.cancel python: client.tests.cancel responses: '200': description: Terminal state after cancellation or an already-terminal run. content: application/json: schema: $ref: '#/components/schemas/TestRun' '202': description: Cancellation has been accepted and is in progress. content: application/json: schema: $ref: '#/components/schemas/TestRun' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/InsufficientScopes' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs: get: operationId: listOrganizations tags: [Organizations] summary: List accessible organizations description: | Returns organizations the caller belongs to, plus tenant organizations visible through an assigned tenant role. This read-only discovery route supplies the `orgId` required by team operations; organization membership and administration remain browser-only. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/organization/organization.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.organizations.list python: client.organizations.list responses: '200': description: Organizations available to the caller. content: application/json: schema: $ref: '#/components/schemas/OrganizationsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: searchCards tags: [Cards] summary: Search project cards description: | Returns a bounded flat card page plus tag, assignee, linked-team, workflow-status, and accessible active/planned sprint filter options. Cards default to open only. Values within one repeated/comma-separated filter are ORed; distinct filter dimensions are ANDed. `includeNoTeam` extends the team facet with cards having no placement, and `includeUnassigned` extends the assignee facet with cards having no user links. Deadline and effort bounds are inclusive. Within either range dimension, its include-no-value flag ORs null-valued cards with bounded non-null matches; using only the flag matches only null-valued cards. Range dimensions AND with every other facet. Invalid instants, negative/non-integer effort values, reversed ranges, and cursors issued for different ranges return canonical 400 errors: `INVALID_CARD_DEADLINE_FILTER`, `INVALID_CARD_DEADLINE_RANGE`, `INVALID_CARD_EFFORT_FILTER`, `INVALID_CARD_EFFORT_RANGE`, or `INVALID_CARD_CURSOR`. Results use an explicit stable sort and opaque cursor. security: - ApiKeyBearer: [] parameters: - $ref: '#/components/parameters/CardQuery' - $ref: '#/components/parameters/CardState' - $ref: '#/components/parameters/CardTagIds' - $ref: '#/components/parameters/CardAssigneeIds' - $ref: '#/components/parameters/CardIncludeUnassigned' - $ref: '#/components/parameters/CardTeamIds' - $ref: '#/components/parameters/CardIncludeNoTeam' - $ref: '#/components/parameters/CardStatusIds' - $ref: '#/components/parameters/CardSprintIds' - $ref: '#/components/parameters/CardDeadlineFrom' - $ref: '#/components/parameters/CardDeadlineTo' - $ref: '#/components/parameters/CardIncludeNoDeadline' - $ref: '#/components/parameters/CardEffortMin' - $ref: '#/components/parameters/CardEffortMax' - $ref: '#/components/parameters/CardIncludeNoEffort' - $ref: '#/components/parameters/CardSort' - $ref: '#/components/parameters/CardPageLimit' - $ref: '#/components/parameters/CardCursor' x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.search python: client.cards.search responses: '200': description: Flat project-card search page. content: application/json: schema: $ref: '#/components/schemas/CardSearchResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createCard tags: [Cards] summary: Create a card description: Creates a project card and records the creation in card history. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.create python: client.cards.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateCardRequest' responses: '201': description: Card created. content: application/json: schema: $ref: '#/components/schemas/CardResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/IdempotencyUnavailable' /api/v2/projects/{projectId}/cards/filter-options: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: getCardFilterOptions tags: [Cards] summary: Get project card filter options description: Returns project tag, assignee, linked-team, workflow-status, and accessible active/planned sprint filter catalogs. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.getFilterOptions python: client.cards.get_filter_options responses: '200': description: Project card tag, assignee, linked-team, status, and sprint options. content: application/json: schema: $ref: '#/components/schemas/CardFilterOptionsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/related: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: listRelatedCards tags: [Cards] summary: List cards related to seed cards description: | Returns direct `relates_to` neighbors and the full connected dependency component for one or more seed cards. Seed cards and cards already on `excludeTeamId` are omitted from the result. At most 50 seeds and 500 related cards are returned; `meta.truncated` reports a larger component. security: - ApiKeyBearer: [] parameters: - name: seedCardIds in: query required: false schema: type: array minItems: 1 maxItems: 50 items: type: string format: uuid style: form explode: true description: Seed card ids, supplied repeatedly or as one comma-separated value. - name: excludeTeamId in: query required: false schema: type: string format: uuid description: Omit related cards already placed on this team board. x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.listRelated python: client.cards.list_related responses: '200': description: Related cards and exclusion counts. content: application/json: schema: $ref: '#/components/schemas/RelatedCardsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/assignable-members: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: listAssignableCardMembers tags: [Cards] summary: List users assignable to project cards description: | Returns only the id and display name of effective project members. This is a read-only assignment catalog; project membership management is not part of this surface. The API key needs `cards:read`, and the acting user must have both card-read and project-member-read permission on the project. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.listAssignableMembers python: client.cards.list_assignable_members responses: '200': description: Users eligible for card assignment. content: application/json: schema: $ref: '#/components/schemas/AssignableCardMembersResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' get: operationId: getCard tags: [Cards] summary: Get a card description: Returns one card owned by the route project. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.get python: client.cards.get responses: '200': description: Card record. content: application/json: schema: $ref: '#/components/schemas/CardResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' patch: operationId: updateCard tags: [Cards] summary: Update a card description: | Updates project-global card fields and appends field-history events. Changing `isOpen` never changes any team workflow placement. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.update python: client.cards.update parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateCardRequest' responses: '200': description: Updated card. content: application/json: schema: $ref: '#/components/schemas/CardResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteCard tags: [Cards] summary: Delete a card description: | Permanently deletes the card. Comments and all card, tag, user, object, and team-board links cascade away; removal and deletion history is recorded. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:manage] x-sdk-methods: typescript: client.cards.delete python: client.cards.delete parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: Card deleted. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/details: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' get: operationId: getCardDetails tags: [Cards] summary: Get card details description: | Returns the card with tags, users, linked cards, design-object references, team placements, the newest 50 comments, and up to 50 newest history events. Use the paginated comment/history routes to continue older timelines. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.getDetails python: client.cards.get_details responses: '200': description: Composite card details. content: application/json: schema: $ref: '#/components/schemas/CardDetails' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/history: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' get: operationId: listCardHistory tags: [Cards] summary: List card history description: Returns card history events newest-first with offset pagination. security: - ApiKeyBearer: [] parameters: - $ref: '#/components/parameters/CardDetailLimit' - $ref: '#/components/parameters/PageOffset' x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.history.list python: client.cards.history.list responses: '200': description: One page of card history events. content: application/json: schema: $ref: '#/components/schemas/CardHistoryPage' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/comments: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' get: operationId: listCardComments tags: [Cards] summary: List card comments description: Returns card comments newest-first with offset pagination. security: - ApiKeyBearer: [] parameters: - $ref: '#/components/parameters/CardDetailLimit' - $ref: '#/components/parameters/PageOffset' x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cards.comments.list python: client.cards.comments.list responses: '200': description: One page of card comments. content: application/json: schema: $ref: '#/components/schemas/CardCommentsPage' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createCardComment tags: [Cards] summary: Add a card comment description: Adds a comment and records it in card history. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.comments.create python: client.cards.comments.create parameters: - $ref: '#/components/parameters/IdempotencyKey' - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CardCommentRequest' responses: '201': description: Comment created. content: application/json: schema: $ref: '#/components/schemas/CardCommentResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/IdempotencyUnavailable' /api/v2/projects/{projectId}/cards/{cardId}/comments/{commentId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' - $ref: '#/components/parameters/CommentId' patch: operationId: updateCardComment tags: [Cards] summary: Edit a card comment description: | Only the comment author may edit its text. API keys require `cards:write`; browser JWT authors may edit their own comment with card-read access. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.comments.update python: client.cards.comments.update parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CardCommentRequest' responses: '200': description: Updated comment. content: application/json: schema: $ref: '#/components/schemas/CardCommentResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteCardComment tags: [Cards] summary: Delete a card comment description: | The comment author or a caller with project `cards:delete` permission may delete it. API keys require `cards:write`; moderation therefore requires a `cards:manage` key so `cards:delete` survives its permission ceiling. Browser JWT authors retain self-service deletion with card-read access. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.comments.delete python: client.cards.comments.delete parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: Comment deleted. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/tags: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' post: operationId: addCardTag tags: [Cards] summary: Add a tag to a card description: | Adds an existing project tag and records the change in card history. Re-adding the same tag is accepted and may return an empty JSON object. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.tags.add python: client.cards.tags.add parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddCardTagRequest' responses: '201': description: Tag attached, or already attached. content: application/json: schema: $ref: '#/components/schemas/CardTagLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' put: operationId: replaceCardTags tags: [Cards] summary: Replace all tags on a card description: Atomically replaces the full tag set and records the add/remove diff in history. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.tags.set python: client.cards.tags.set parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ReplaceCardTagsRequest' responses: '200': description: Current full tag set. content: application/json: schema: $ref: '#/components/schemas/CardTagsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/tags/{tagId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' - $ref: '#/components/parameters/TagId' delete: operationId: removeCardTag tags: [Cards] summary: Remove a tag from a card description: Removes the tag link and records the change in card history. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.tags.remove python: client.cards.tags.remove parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: Tag detached. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/user-links: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' post: operationId: addCardUserLink tags: [Cards] summary: Link a user to a card description: | Links a user in a named relation, defaulting to `participant`, and records the change in history. Re-adding the same relation is accepted and may return an empty JSON object. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.userLinks.add python: client.cards.user_links.add parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddCardUserLinkRequest' responses: '201': description: User relation attached, or already attached. content: application/json: schema: $ref: '#/components/schemas/CardUserLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/user-links/{linkId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' - $ref: '#/components/parameters/LinkId' delete: operationId: removeCardUserLink tags: [Cards] summary: Remove a user link from a card description: Removes the identified assignee or participant relation from the card. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.userLinks.remove python: client.cards.user_links.remove parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: User relation removed. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/card-links: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' post: operationId: addCardLink tags: [Cards] summary: Link two cards description: | Links two cards in the same project. `dependency_of` reverses the stored direction and is returned from the opposite card's perspective. Dependency cycles are rejected. Re-adding an identical link is accepted and may return an empty JSON object. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.cardLinks.add python: client.cards.card_links.add parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddCardLinkRequest' responses: '201': description: Card link created, or already present. content: application/json: schema: $ref: '#/components/schemas/CardLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/card-links/{linkId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' - $ref: '#/components/parameters/LinkId' delete: operationId: removeCardLink tags: [Cards] summary: Remove a card-to-card link description: Removes the single stored link and records history on both cards. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.cardLinks.remove python: client.cards.card_links.remove parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: Card link removed. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/object-links: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' post: operationId: addCardObjectLink tags: [Cards] summary: Link a design object to a card description: | Verifies an object in the current project branch, resolves its canonical name and type server-side, and records the branch-scoped reference in card history. `branch` overrides a branch embedded in the project id; otherwise the branch defaults to `main`. security: - ApiKeyBearer: [] parameters: - name: branch in: query required: false schema: type: string description: Branch containing the referenced object. - $ref: '#/components/parameters/IfMatch' x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write, projects:read] x-sdk-methods: typescript: client.cards.objectLinks.add python: client.cards.object_links.add requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddCardObjectLinkRequest' responses: '201': description: Current object-link record. content: application/json: schema: $ref: '#/components/schemas/CardObjectLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/cards/{cardId}/object-links/{linkId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/CardId' - $ref: '#/components/parameters/LinkId' delete: operationId: removeCardObjectLink tags: [Cards] summary: Remove a design-object link description: Removes the reference and records it in card history. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cards.objectLinks.remove python: client.cards.object_links.remove parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: Object link removed. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/projects/{projectId}/card-tags: parameters: - $ref: '#/components/parameters/ProjectId' get: operationId: listCardTags tags: [Cards] summary: List the project's card-tag catalog description: Returns every project card tag with its current card usage count. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:read] x-sdk-methods: typescript: client.cardTags.list python: client.card_tags.list responses: '200': description: Project tags with card usage counts. content: application/json: schema: $ref: '#/components/schemas/CardTagCatalogResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createCardTag tags: [Cards] summary: Create a card tag description: Creates a uniquely named tag in the project card catalog. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cardTags.create python: client.card_tags.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateCardTagRequest' responses: '201': description: Card tag created. content: application/json: schema: $ref: '#/components/schemas/CardTagResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/IdempotencyUnavailable' /api/v2/projects/{projectId}/card-tags/{tagId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/TagId' patch: operationId: updateCardTag tags: [Cards] summary: Update a card tag description: Updates the name, description, color, or lifecycle status of a card tag. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:write] x-sdk-methods: typescript: client.cardTags.update python: client.card_tags.update requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateCardTagRequest' responses: '200': description: Updated card tag. content: application/json: schema: $ref: '#/components/schemas/CardTagResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteCardTag tags: [Cards] summary: Delete a card tag description: Permanently deletes the catalog tag and cascades all card-tag links. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/card/card.routes.js x-required-scopes: [cards:manage] x-sdk-methods: typescript: client.cardTags.delete python: client.card_tags.delete requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ExpectedHistoryHeadsRequest' responses: '204': description: Card tag deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams: parameters: - $ref: '#/components/parameters/OrgId' get: operationId: listTeams tags: [Teams] summary: List visible teams description: | Returns only teams visible to the caller: explicit memberships, internal teams for organization members, and all teams for the organization owner. The list never reveals inaccessible private teams. security: - ApiKeyBearer: [] parameters: - name: status in: query required: false schema: type: string description: Exact team lifecycle status to include. - name: include in: query required: false schema: type: string enum: [work-summary] description: | Include open-card counts and planning sprint summaries. This expansion additionally requires effective `teams:sprints:read` permission. x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.list python: client.teams.list responses: '200': description: Teams visible in the organization. content: application/json: schema: $ref: '#/components/schemas/TeamsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createTeam tags: [Teams] summary: Create a team description: | Creates a team, makes the caller its owner, and seeds `Not started`, `In progress`, and `Done` workflow statuses. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:manage] x-sdk-methods: typescript: client.teams.create python: client.teams.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateTeamRequest' responses: '201': description: Team created. content: application/json: schema: $ref: '#/components/schemas/TeamResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/IdempotencyUnavailable' /api/v2/orgs/{orgId}/teams/{teamId}: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: getTeam tags: [Teams] summary: Get a team description: | Returns team metadata and the caller's effective team permissions. A private or cross-organization team the caller cannot access is reported as not found. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.get python: client.teams.get responses: '200': description: Team and effective viewer capabilities. content: application/json: schema: $ref: '#/components/schemas/GetTeamResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' patch: operationId: updateTeam tags: [Teams] summary: Update a team description: Updates operational team metadata when the caller may manage the team. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write] x-sdk-methods: typescript: client.teams.update python: client.teams.update requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTeamRequest' responses: '200': description: Updated team. content: application/json: schema: $ref: '#/components/schemas/TeamResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteTeam tags: [Teams] summary: Delete a team description: | Permanently deletes the team. Its statuses, sprints, memberships, linked projects, and board placements cascade away; project cards remain. Because placements are removed, the caller must be able to write every affected project card. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:manage, cards:write] x-sdk-methods: typescript: client.teams.delete python: client.teams.delete requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ExpectedHistoryHeadsRequest' responses: '204': description: Team deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/index: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: getTeamIndex tags: [Teams] summary: Get the team board index description: | Returns team metadata, workflow statuses, sprints, board cards, and viewer capabilities. API-key requests default to 100 cards and may request up to 500; browser requests remain unbounded when pagination is omitted. security: - ApiKeyBearer: [] parameters: - $ref: '#/components/parameters/CardPageLimit' - $ref: '#/components/parameters/PageOffset' x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.getIndex python: client.teams.get_index responses: '200': description: Composite team board index. content: application/json: schema: $ref: '#/components/schemas/TeamIndex' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/overview: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: getTeamOverview tags: [Teams] summary: Get active team planning work description: | Returns team metadata, workflow statuses, active and planned sprints, placed cards outside completed sprints, the completed-sprint count, and effective viewer capabilities. The card page is always bounded and defaults to 500. security: - ApiKeyBearer: [] parameters: - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 500 default: 500 description: Maximum active-work cards returned. - $ref: '#/components/parameters/PageOffset' - $ref: '#/components/parameters/CardSort' x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.getOverview python: client.teams.get_overview responses: '200': description: Bounded active team planning work. content: application/json: schema: $ref: '#/components/schemas/TeamOverview' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/reports: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: getTeamReports tags: [Teams] summary: Get the team reports summary description: | Returns a board index plus the number of distinct cards completed in the last seven days. API-key requests default to 100 cards and may request up to 500; browser requests remain unbounded when pagination is omitted. The acting user's live role must include `teams:sprints:analysis:read`. security: - ApiKeyBearer: [] parameters: - $ref: '#/components/parameters/CardPageLimit' - $ref: '#/components/parameters/PageOffset' - name: sprint in: query required: false schema: type: string format: uuid description: Include and select this archived sprint for a reports deep link. x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.getReports python: client.teams.get_reports responses: '200': description: Board index and report statistics. content: application/json: schema: $ref: '#/components/schemas/TeamReports' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/charts: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: getTeamChart tags: [Teams] summary: Get team analytics description: | Returns sprint velocity by default or a daily cumulative-flow series. Explicit cumulative-flow ranges are capped to 90 days; an omitted range covers the team's full history. The acting user's live role must include `teams:sprints:analysis:read`. security: - ApiKeyBearer: [] parameters: - name: type in: query required: false schema: type: string enum: [velocity, cumulative-flow] default: velocity - name: from in: query required: false schema: $ref: '#/components/schemas/SprintDateInput' - name: to in: query required: false schema: $ref: '#/components/schemas/SprintDateInput' - name: projectIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: false description: Limit cumulative-flow results to these linked projects. x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.getChart python: client.teams.get_chart responses: '200': description: Requested team chart. content: application/json: schema: oneOf: - $ref: '#/components/schemas/TeamVelocityChart' - $ref: '#/components/schemas/TeamCumulativeFlowChart' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/projects: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: listTeamProjects tags: [Teams] summary: List projects linked to a team description: Returns the projects whose cards may be placed on this team board. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.projects.list python: client.teams.projects.list responses: '200': description: Linked project database records. content: application/json: schema: $ref: '#/components/schemas/TeamProjectsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: addTeamProject tags: [Teams] summary: Link a project to a team description: | Links an existing project owned by the route's organization. Re-linking an existing project is accepted and may return an empty JSON object. The caller must also be able to read Cards in the Project. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:manage, cards:read] x-sdk-methods: typescript: client.teams.projects.add python: client.teams.projects.add requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddTeamProjectRequest' responses: '201': description: Project link created, or already present. content: application/json: schema: $ref: '#/components/schemas/TeamProjectLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/projects/{projectId}: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/TeamProjectId' delete: operationId: removeTeamProject tags: [Teams] summary: Unlink a project from a team description: | Removes the project link only when no cards from that project remain on the Team board. Move or remove those cards first. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:manage, cards:read] x-sdk-methods: typescript: client.teams.projects.remove python: client.teams.projects.remove responses: '204': description: Project unlinked. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/statuses: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: listTeamStatuses tags: [Teams] summary: List team workflow statuses description: Returns the ordered status columns configured for the team board. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.statuses.list python: client.teams.statuses.list responses: '200': description: Ordered workflow statuses. content: application/json: schema: $ref: '#/components/schemas/TeamStatusesResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: createTeamStatus tags: [Teams] summary: Create a workflow status description: Creates a new ordered status column for the team board. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write] x-sdk-methods: typescript: client.teams.statuses.create python: client.teams.statuses.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateTeamStatusRequest' responses: '201': description: Workflow status created. content: application/json: schema: $ref: '#/components/schemas/TeamStatusResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/IdempotencyUnavailable' /api/v2/orgs/{orgId}/teams/{teamId}/statuses/{statusId}: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/StatusId' patch: operationId: updateTeamStatus tags: [Teams] summary: Update a workflow status description: Updates a team status name, order, analytics state, or card-entry action. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write] x-sdk-methods: typescript: client.teams.statuses.update python: client.teams.statuses.update requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTeamStatusRequest' responses: '200': description: Updated workflow status. content: application/json: schema: $ref: '#/components/schemas/TeamStatusResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteTeamStatus tags: [Teams] summary: Delete a workflow status description: | Moves every card in this column to `moveToStatusId` before deleting it. Moving into an `automatic` destination closes open project cards. A destination with `assignMoverOnEntry` assigns the caller to each card when needed. For API-key requests, the caller is the key's owning user. No move reopens a card or changes another team's placement. The destination must belong to the same team. Required fields are enforced for every migrated card unless the caller explicitly bypasses them. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:manage, cards:write] x-sdk-methods: typescript: client.teams.statuses.delete python: client.teams.statuses.delete requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DeleteTeamStatusRequest' responses: '204': description: Workflow status deleted and cards reassigned. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '422': $ref: '#/components/responses/CardStatusFieldsRequired' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/statuses/{statusId}/closures: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/StatusId' post: operationId: closeTeamStatusCards tags: [Teams] summary: Close every open card in a workflow status description: | Atomically closes every still-open project card currently placed in this team status. Bulk close is available on every workflow status. The caller must be able to write every affected project; any denial or stale history head rolls back the complete operation. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.statuses.closeAll python: client.teams.statuses.close_all requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ExpectedHistoryHeadsRequest' responses: '200': description: Bounded summary of cards closed by the transaction. content: application/json: schema: $ref: '#/components/schemas/CloseTeamStatusCardsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/sprints: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' post: operationId: createTeamSprint tags: [Teams] summary: Create a planned sprint description: New sprints are always created in the `planned` lifecycle state. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write] x-sdk-methods: typescript: client.teams.sprints.create python: client.teams.sprints.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateTeamSprintRequest' responses: '201': description: Planned sprint created. content: application/json: schema: $ref: '#/components/schemas/TeamSprintResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/IdempotencyUnavailable' /api/v2/orgs/{orgId}/teams/{teamId}/sprints/completed: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: listCompletedTeamSprints tags: [Teams] summary: List completed team sprints description: | Returns completed sprints in stable newest-ended order with each sprint's current placed-card count. Search is case-insensitive across sprint name and description. Date bounds apply to sprint end dates. security: - ApiKeyBearer: [] parameters: - name: search in: query required: false schema: type: string maxLength: 100 description: Case-insensitive sprint name or description search. - name: from in: query required: false schema: type: string format: date description: Include sprints ending on or after this UTC date. - name: to in: query required: false schema: type: string format: date description: Include sprints ending on or before this UTC date. - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 50 default: 25 - $ref: '#/components/parameters/PageOffset' x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.sprints.listCompleted python: client.teams.sprints.list_completed responses: '200': description: Completed sprint page. content: application/json: schema: $ref: '#/components/schemas/CompletedTeamSprintsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/sprints/{sprintId}: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/SprintId' get: operationId: getTeamSprint tags: [Teams] summary: Get a sprint description: Returns one sprint after confirming it belongs to the route team. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.sprints.get python: client.teams.sprints.get responses: '200': description: Sprint record. content: application/json: schema: $ref: '#/components/schemas/TeamSprintResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' patch: operationId: updateTeamSprint tags: [Teams] summary: Update sprint details description: Sprint lifecycle state cannot be changed here; use the start and complete actions. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write] x-sdk-methods: typescript: client.teams.sprints.update python: client.teams.sprints.update requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTeamSprintRequest' responses: '200': description: Updated sprint. content: application/json: schema: $ref: '#/components/schemas/TeamSprintResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteTeamSprint tags: [Teams] summary: Delete a sprint description: | Active sprints must be completed first. A planned or completed sprint must also be empty; move or remove every card before deleting it. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:manage] x-sdk-methods: typescript: client.teams.sprints.delete python: client.teams.sprints.delete responses: '204': description: Empty sprint deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/sprints/{sprintId}/start: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/SprintId' post: operationId: startTeamSprint tags: [Teams] summary: Start a planned sprint description: | Starts a planned sprint that contains at least one card. Another active sprint causes a conflict unless `allowConcurrent` is explicitly true. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write] x-sdk-methods: typescript: client.teams.sprints.start python: client.teams.sprints.start requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/StartTeamSprintRequest' responses: '200': description: Active sprint. content: application/json: schema: $ref: '#/components/schemas/TeamSprintResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/sprints/{sprintId}/complete: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/SprintId' post: operationId: completeTeamSprint tags: [Teams] summary: Complete an active sprint description: | Marks an active sprint completed. Finished cards stay attached for reporting; unfinished cards move to the backlog or to the specified planned sprint. Each movement is recorded in card and sprint history. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.sprints.complete python: client.teams.sprints.complete requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CompleteTeamSprintRequest' responses: '200': description: Completed sprint. content: application/json: schema: $ref: '#/components/schemas/TeamSprintResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/sprints/{sprintId}/details: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/SprintId' get: operationId: getTeamSprintDetails tags: [Teams] summary: Get sprint details description: Returns the sprint, its current cards, and the team's workflow statuses. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.sprints.getDetails python: client.teams.sprints.get_details responses: '200': description: Composite sprint details. content: application/json: schema: $ref: '#/components/schemas/TeamSprintDetails' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/sprints/{sprintId}/charts: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/SprintId' get: operationId: getTeamSprintChart tags: [Teams] summary: Get sprint burndown or burnup description: | Replays card scope, effort edits, and status changes into UTC daily buckets. Future sprint days have null actual values. The acting user's live role must include `teams:sprints:analysis:read`. security: - ApiKeyBearer: [] parameters: - name: type in: query required: false schema: type: string enum: [burndown, burnup] default: burndown x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.sprints.getChart python: client.teams.sprints.get_chart responses: '200': description: Requested sprint chart. content: application/json: schema: $ref: '#/components/schemas/TeamSprintChart' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/available-cards: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: searchAvailableTeamCards tags: [Teams] summary: Search linked-Project Cards available to add description: | Searches open Cards from already-linked Projects where the actor has effective Card write access, excluding Cards already placed on this Team. Project authorization is intersected with the credential ceiling before the bounded database query. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.cards.searchAvailable python: client.teams.cards.search_available parameters: - name: q in: query required: false schema: type: string maxLength: 200 description: Case-insensitive Card name, description, and Resolution search. - name: projectIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: false description: Optional subset of eligible linked Projects. - name: excludeProjectIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: false description: | Optional linked Projects to exclude when searching all eligible Projects. Mutually exclusive with `projectIds`. - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 50 - name: cursor in: query required: false schema: type: string maxLength: 1024 description: Opaque cursor returned by the preceding page. responses: '200': description: Available Cards and eligible linked-Project filters. content: application/json: schema: $ref: '#/components/schemas/AvailableTeamCardsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/project-cards: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' post: operationId: createTeamProjectCard tags: [Teams] summary: Atomically create and place a Project Card description: | Creates a Project-owned Card, optionally assigns an effective Project member, links the Project when separately authorized, and places the Card on this Team board in one transaction. The selected Status and Sprint policy are revalidated under the Team lock before any row is inserted. A status with `assignMoverOnEntry` assigns the caller, using the API key's owning user for API-key requests. Destination required fields are enforced unless explicitly bypassed. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.cards.create python: client.teams.cards.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateTeamProjectCardRequest' responses: '201': description: Project Card, Team placement, and current history head. content: application/json: schema: $ref: '#/components/schemas/CreateTeamProjectCardResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/CardStatusFieldsRequired' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/cards: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' get: operationId: listTeamCards tags: [Teams] summary: List cards on a team board description: | Returns filtered Team card rows. Use `sprintId=null` to select the backlog. Multi-value facets are ORed within one dimension and ANDed across dimensions. API-key requests default to 100 cards and all callers may request up to 500. security: - ApiKeyBearer: [] parameters: - name: sprintId in: query required: false schema: oneOf: - type: string format: uuid - type: string const: 'null' description: Sprint id, or the literal `null` for cards not in a sprint. - name: statusId in: query required: false schema: type: string format: uuid - name: isOpen in: query required: false schema: type: boolean - $ref: '#/components/parameters/CardQuery' - $ref: '#/components/parameters/CardState' - $ref: '#/components/parameters/CardTagIds' - $ref: '#/components/parameters/CardAssigneeIds' - $ref: '#/components/parameters/CardIncludeUnassigned' - $ref: '#/components/parameters/CardStatusIds' - $ref: '#/components/parameters/CardSprintIds' - $ref: '#/components/parameters/CardDeadlineFrom' - $ref: '#/components/parameters/CardDeadlineTo' - $ref: '#/components/parameters/CardIncludeNoDeadline' - $ref: '#/components/parameters/CardEffortMin' - $ref: '#/components/parameters/CardEffortMax' - $ref: '#/components/parameters/CardIncludeNoEffort' - $ref: '#/components/parameters/CardSort' - name: projectIds in: query required: false description: Repeated or comma-separated Project IDs. schema: type: array items: type: string format: uuid style: form explode: true - name: includeFilterOptions in: query required: false description: Include distinct Team card filter catalogs in the response. schema: type: boolean default: false - $ref: '#/components/parameters/CardPageLimit' - $ref: '#/components/parameters/PageOffset' x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:read] x-sdk-methods: typescript: client.teams.cards.list python: client.teams.cards.list responses: '200': description: Filtered board cards. content: application/json: schema: $ref: '#/components/schemas/TeamCardsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' post: operationId: addTeamCard tags: [Teams] summary: Add a card to a team board description: | Places a card on the board and records linked history. A new placement defaults to the backlog and first not-started status. For an existing placement, an omitted sprint or status preserves its current value; a null sprint explicitly moves it to the backlog, while a null status also preserves its current status. If the card's project is not linked, it is linked automatically only when the caller may add team projects. Entering an `automatic` status closes an open card. A status with `assignMoverOnEntry` adds the caller as an assignee if needed; API-key requests use the key's owning user. Both actions may apply together. No status ever reopens a card. Destination required fields are enforced unless explicitly bypassed. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.cards.add python: client.teams.cards.add parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddTeamCardRequest' responses: '201': description: Current board placement. content: application/json: schema: $ref: '#/components/schemas/TeamCardLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '422': $ref: '#/components/responses/CardStatusFieldsRequired' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/cards/{cardId}/sprint-link: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/CardId' patch: operationId: updateTeamCardSprint tags: [Teams] summary: Move a board card between sprints description: | Moves the card to a sprint on this team, or to the backlog when `sprintId` is null, and records both sides of the membership change. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.cards.updateSprint python: client.teams.cards.update_sprint parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTeamCardSprintRequest' responses: '200': description: Updated board placement. content: application/json: schema: $ref: '#/components/schemas/TeamCardLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/cards/{cardId}/status: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/CardId' patch: operationId: updateTeamCardStatus tags: [Teams] summary: Change a board card's workflow status description: | Moves the card on this team only and records the change. Entering an `automatic` status closes an open project card. `off` and `manual` do not change project lifecycle. A status with `assignMoverOnEntry` adds the caller as an assignee if needed; API-key requests use the key's owning user. Close behavior and assignment may apply together. No status transition reopens a card. `cardUpdates` are applied and validated in the same transaction before required-field policy is evaluated. A bypass must be explicitly requested. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.cards.updateStatus python: client.teams.cards.update_status parameters: - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTeamCardStatusRequest' responses: '200': description: Updated board placement. content: application/json: schema: $ref: '#/components/schemas/TeamCardLinkResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '422': $ref: '#/components/responses/CardStatusFieldsRequired' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /api/v2/orgs/{orgId}/teams/{teamId}/cards/{cardId}: parameters: - $ref: '#/components/parameters/OrgId' - $ref: '#/components/parameters/TeamId' - $ref: '#/components/parameters/CardId' delete: operationId: removeTeamCard tags: [Teams] summary: Remove a card from a team board description: Removes only the board placement and records linked history; the project card remains. security: - ApiKeyBearer: [] x-routing-server-source: RoutingServer/team/team.routes.js x-required-scopes: [teams:write, cards:write] x-sdk-methods: typescript: client.teams.cards.remove python: client.teams.cards.remove parameters: - $ref: '#/components/parameters/IfMatch' responses: '204': description: Card removed from this team board. headers: ETag: $ref: '#/components/headers/CardHistoryETag' X-Card-History-Head-Id: $ref: '#/components/headers/CardHistoryHeadId' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/CardHistoryConflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' components: securitySchemes: ApiKeyBearer: type: http scheme: bearer bearerFormat: dav_ak_live_... or dav_ak_test_... x-default: dav_ak_live_your_token description: | Personal access token. The scopes granted at issuance determine both which operations the key may call and the ceiling on the resource permissions it can exercise. Each scope family is a ladder: `projects:manage` implies `projects:write` and `projects:read`; `cards:manage` implies `cards:write` and `cards:read`; and `teams:manage` implies `teams:write` and `teams:read`. These are named API capability bundles, not blanket domain roles: `manage` exposes only the permissions enumerated for that scope and never bypasses the acting user's current role-based access. GrantBearer: type: http scheme: bearer bearerFormat: dav_gr_... x-default: dav_gr_your_grant description: | A session's data-plane grant, from `dataPlane.token`. Valid only on the data-plane host, only for the one project its session opened, and only for minutes. A grant is not an API key and the two are not interchangeable: presenting a grant to a control-plane operation is rejected, and an API key is not accepted on the data plane. The separation is deliberate — a grant is meant to be cheap to lose, so it reaches one project, does no more than the key that minted it, and is revoked when its session closes. ExecutionGrantBearer: type: http scheme: bearer bearerFormat: dav_gr_... (purpose=automation) x-default: dav_gr_execution_grant description: | The grant injected into a running Code object's container. It delegates the reach of whoever started the execution over the one project the Code object lives in, and it expires with the container. On this mount it can create, inspect, and clean up the evaluation sandboxes that execution owns. It cannot select an existing project as a target, and a sandbox-bound `purpose=evaluation` grant is refused here so an evaluation cannot start another one. parameters: IdempotencyKey: name: Idempotency-Key in: header required: false schema: type: string maxLength: 255 description: | A value you choose to identify this request, so that retrying it does not repeat its effect. Reuse the same key when retrying and the original result is returned; use a fresh key when you mean to create something new. Keys are scoped to the API key that sent them (or to the user for browser sessions). Replayed responses include `Idempotency-Replayed: true`. ProjectId: name: projectId in: path required: true schema: type: string minLength: 1 description: Project id. May be compound in the form `{projectId}--{branchName}`. TeamProjectId: name: projectId in: path required: true schema: type: string format: uuid description: Bare id of a project linked to a team. OrgId: name: orgId in: path required: true schema: type: string format: uuid description: Organization id. TeamId: name: teamId in: path required: true schema: type: string format: uuid description: Agile team id. CardId: name: cardId in: path required: true schema: type: string format: uuid description: Agile card id. TagId: name: tagId in: path required: true schema: type: string format: uuid description: Card-tag id. CommentId: name: commentId in: path required: true schema: type: string format: uuid description: Card-comment id. LinkId: name: linkId in: path required: true schema: type: string format: uuid description: Card relation junction-row id. SprintId: name: sprintId in: path required: true schema: type: string format: uuid description: Team sprint id. StatusId: name: statusId in: path required: true schema: type: string format: uuid description: Team workflow-status id. CardQuery: name: q in: query required: false schema: type: string maxLength: 200 description: Case-insensitive substring search across card name, description, and resolution. CardState: name: state in: query required: false schema: type: string enum: [open, closed, all] default: open description: Project-global card lifecycle state. CardTagIds: name: tagIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: true description: Match cards carrying any selected project tag. CardAssigneeIds: name: assigneeIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: true description: Match cards assigned to any selected project member. CardIncludeUnassigned: name: includeUnassigned in: query required: false schema: type: boolean default: false description: OR cards with no user links into the assignee facet. This is not a sentinel assignee ID. CardTeamIds: name: teamIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: true description: Match cards placed on any selected linked team. CardIncludeNoTeam: name: includeNoTeam in: query required: false schema: type: boolean default: false description: OR cards with no team placement into the team facet. This is not a sentinel team ID. CardStatusIds: name: statusIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: true description: Match cards whose selected-team placement uses any selected status. CardSprintIds: name: sprintIds in: query required: false schema: type: array maxItems: 50 items: type: string format: uuid style: form explode: true description: Match cards whose team placement uses any selected sprint. CardDeadlineFrom: name: deadlineFrom in: query required: false schema: type: string format: date-time description: Inclusive ISO 8601 instant lower bound for non-null card deadlines. CardDeadlineTo: name: deadlineTo in: query required: false schema: type: string format: date-time description: Inclusive ISO 8601 instant upper bound for non-null card deadlines. CardIncludeNoDeadline: name: includeNoDeadline in: query required: false schema: type: boolean default: false description: OR cards with a null deadline into bounded deadline matches. With no deadline bounds, match only cards with no deadline. CardEffortMin: name: effortMin in: query required: false schema: type: integer minimum: 0 description: Inclusive lower bound for non-null card effort. CardEffortMax: name: effortMax in: query required: false schema: type: integer minimum: 0 description: Inclusive upper bound for non-null card effort. CardIncludeNoEffort: name: includeNoEffort in: query required: false schema: type: boolean default: false description: OR cards with null effort into bounded effort matches. With no effort bounds, match only cards with no effort. CardSort: name: sort in: query required: false schema: type: string enum: - created_asc - created_desc - updated_asc - updated_desc - deadline_asc - deadline_desc - effort_asc - effort_desc - name_asc - name_desc default: created_desc description: Stable card sort; card ID is the deterministic tie-breaker. CardPageLimit: name: limit in: query required: false schema: type: integer minimum: 1 maximum: 500 default: 100 description: Maximum cards returned. CardCursor: name: cursor in: query required: false schema: type: string maxLength: 2048 description: Opaque cursor returned as `meta.nextCursor` or `meta.previousCursor`. IfMatch: name: If-Match in: header required: false schema: type: string maxLength: 132 description: | Quoted or unquoted latest card `historyHeadId`. When the request body also contains `expectedHistoryHeadId`, both values must match. A stale head returns `409 CARD_HISTORY_CONFLICT` without applying the mutation. CardDetailLimit: name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 50 PageOffset: name: offset in: query required: false schema: type: integer minimum: 0 default: 0 FileId: name: fileId in: path required: true schema: type: string minLength: 1 description: Reference object id or storage filename. Branch: name: branch in: query required: false schema: type: string default: main BranchPath: name: branch in: path required: true schema: type: string minLength: 1 description: Branch name. ObjectId: name: objectId in: path required: true schema: type: string minLength: 1 description: Id of an object in the project. SessionId: name: sessionId in: path required: true schema: type: string format: uuid description: Session id from `createSession`. TestId: name: testId in: path required: true schema: type: string minLength: 1 description: Id of the authored Test object in the source project. RunId: name: runId in: path required: true schema: type: string format: uuid description: Evaluation-run or Test-run id returned by its create operation. DataPlaneOwnerId: name: ownerId in: path required: true schema: type: string minLength: 1 description: | Id of the account or organization that owns the project, from the project's `ownerId`. DataPlaneUserId: name: userId in: path required: true schema: type: string minLength: 1 description: | Acting user id. Ignored for authorization — the acting identity comes from the grant, so this cannot be used to act as someone else. DataPlaneProjectId: name: projectId in: path required: true schema: type: string minLength: 1 description: | Project id, compound as `{projectId}--{branchName}`. Must be the project the session opened. ConnectionId: name: connectionId in: path required: true schema: type: string pattern: '^headless-' description: | The session's `dataPlane.connectionId`, which is `headless-{sessionId}`. Send what the session gave you and this is the only value you will ever need. What the server actually requires is the `headless-` prefix, and the difference matters in one place: a Code object addresses the data plane with `headless-exec-{executionId}`, because an execution holds a grant rather than a session. The prefix is what makes the upload be applied through a client, so the reference joins the parts tree instead of the bytes landing in storage with nothing pointing at them. An id naming no live connection is served by an ephemeral one. ParentId: name: parentId in: path required: true schema: type: string minLength: 1 description: Id of the parts-tree object the file is attached under. FileName: name: fileName in: path required: true schema: type: string minLength: 1 description: Stored filename, in the form `{fileId}.{extension}`. UsageFrom: name: from in: query required: false schema: type: string format: date-time description: | Only count events at or after this time. Omit for all of recorded history. UsageTo: name: to in: query required: false schema: type: string format: date-time description: Only count events at or before this time. UsageGroupBy: name: groupBy in: query required: false schema: type: string enum: [model, project, session, day] description: | Break the totals down. Omit to receive totals only — `totals` is always present and always covers the whole scope, whether or not you group. headers: CardHistoryETag: description: Quoted latest card history head after the committed mutation. schema: type: string CardHistoryHeadId: description: Latest card history head after the committed mutation. schema: type: string format: uuid responses: BadRequest: description: | Malformed request parameters or body. Agile requests may return `INVALID_PAGINATION` or `INVALID_IDEMPOTENCY_KEY`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' Unauthorized: description: | No credential was supplied, or the supplied credential is malformed, expired, or revoked. A credential that is present but unusable is never downgraded to an anonymous request. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' InsufficientScopes: description: API key lacks a required scope. Error code is `INSUFFICIENT_SCOPES`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' Forbidden: description: | Authenticated but not authorized. Either the acting user lacks the required resource permission, the key's scope ceiling excludes it, or the endpoint rejects this credential type (`CREDENTIAL_NOT_PERMITTED`). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' NotFound: description: | The resource does not exist in the parent named by the path, or is hidden from the caller. Absence and privacy denial are deliberately indistinguishable so project, organization, and private-team existence cannot be probed. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' GrantRejected: description: | The grant is missing, unknown, expired, or revoked. These are one response so a rejected request cannot be used to learn which grants exist. Refresh the session to get a new grant, or create a new session if that also fails. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' ProjectMoved: description: | The project moved to another machine. Error code is `PROJECT_MOVED`. Retry the request: the next one resolves to the machine holding it now, at the same URL. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' ProjectNotRunning: description: | The project stopped running between being opened for this request and the request reaching it. Error code is `PROJECT_NOT_RUNNING`. Retry: the next call opens it again. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' ProjectNotReady: description: | The project could not be opened in time, or no machine is currently available to run it. Error codes are `PROJECT_NOT_READY`, `SERVER_NOT_AVAILABLE`, and `SERVICE_UNAVAILABLE`. Retry after the interval in `Retry-After`. headers: Retry-After: schema: type: integer minimum: 1 description: Seconds to wait before retrying. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' GitFailed: description: | The git operation failed inside the engine rather than being refused. Error code is `GIT_OPERATION_FAILED`, or `CHANGES_UNAVAILABLE` and `COMMIT_NOT_RECORDED` for the two cases where a specific step is known to have produced nothing. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' RateLimited: description: Request rate exceeded, either globally or for this key. headers: Retry-After: schema: type: integer minimum: 1 description: Seconds to wait before retrying. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' InternalError: description: Unexpected server error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' Conflict: description: | The resource's current state no longer permits this operation, or a unique name, hierarchy, dependency, or lifecycle invariant would be violated. Examples include an active sprint that must be completed first, a duplicate card-tag name (`TAG_NAME_CONFLICT`), or a dependency cycle. Idempotent creates may return `IDEMPOTENCY_KEY_REUSED` or `IDEMPOTENCY_REQUEST_IN_PROGRESS`; the latter includes `Retry-After`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' CardHistoryConflict: description: | The supplied `If-Match`, `expectedHistoryHeadId`, or `expectedHistoryHeadIds` no longer matches committed card history. Error code is `CARD_HISTORY_CONFLICT`; `error.details` includes the expected head, current head and sequence, plus recent card activity. No part of the requested card mutation is applied. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' CardStatusFieldsRequired: description: | The destination status requires card fields that are currently missing. Error code is `CARD_STATUS_FIELDS_REQUIRED`; `error.details` includes `teamId`, `statusId`, `statusName`, and `missingFields`. Supply the fields atomically or explicitly set `bypassRequiredFields=true`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' IdempotencyUnavailable: description: | Idempotency protection is temporarily unavailable. Error code is `IDEMPOTENCY_UNAVAILABLE`; the response includes `Retry-After`. headers: Retry-After: schema: type: integer minimum: 1 description: Seconds to wait before retrying. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' InfrastructureFailure: description: | The request was understood, but required evaluation infrastructure or evidence was unavailable. Error codes include `EVALUATION_SCOPE_MISSING`, `EVALUATION_AGENT_FAILED`, `EVALUATION_TIMEOUT`, `EVALUATION_EVIDENCE_MISSING`, `EVALUATION_OBSERVATION_INVALID`, and `EVALUATION_CLEANUP_FAILED`. These conditions are never converted to a successful quality observation or a skipped Test. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' schemas: NullableHistoryHeadId: type: [string, 'null'] format: uuid description: Latest committed card-history row ID; null only before a card has history. HistoryHeadSequence: type: string pattern: '^\d+$' description: Globally monotonic card-history sequence. NullableHistoryHeadSequence: type: [string, 'null'] pattern: '^\d+$' description: Globally monotonic card-history sequence. ExpectedHistoryHeadsRequest: type: object properties: expectedHistoryHeadIds: type: object additionalProperties: $ref: '#/components/schemas/NullableHistoryHeadId' description: Latest known history head keyed by every card the bulk write may affect. additionalProperties: false OrganizationSummary: type: object required: - id - name - slug - handle - description - visibility - createdAt - updatedAt - isFrozen - isTeamOwned properties: id: type: string format: uuid name: type: string slug: type: string handle: type: string description: type: string visibility: type: string createdAt: type: [string, 'null'] format: date-time updatedAt: type: [string, 'null'] format: date-time isFrozen: type: boolean isTeamOwned: type: boolean memberCount: type: integer minimum: 0 joinedAt: type: [string, 'null'] format: date-time role: type: string roleName: type: string ownedProjectCount: type: integer minimum: 0 maxOwnedProjects: type: integer minimum: 0 additionalProperties: false OrganizationsResponse: type: object required: [orgs] properties: orgs: type: array items: $ref: '#/components/schemas/OrganizationSummary' additionalProperties: false AgileCard: type: object required: - id - name - description - resolution - created_by_user - created_at - updated_at - deadline - is_open - project_id - effort properties: &AgileCardProperties id: type: string format: uuid name: type: string description: type: [string, 'null'] resolution: type: [string, 'null'] maxLength: 10000 description: Optional Markdown resolution; closing or reopening the card does not clear it. created_by_user: type: [string, 'null'] format: uuid author_display_name: type: [string, 'null'] description: Display name of the user who created the card, when available. created_at: type: [string, 'null'] format: date-time closed_at: type: [string, 'null'] format: date-time readOnly: true description: Timestamp of the latest transition to the closed state; null while open. updated_at: type: [string, 'null'] format: date-time deadline: type: [string, 'null'] format: date-time is_open: type: boolean project_id: type: string format: uuid effort: type: [integer, 'null'] minimum: 0 description: Unit-agnostic estimate, commonly interpreted as story points or hours. additionalProperties: true CardResponse: type: object required: [card, historyHeadId, historyHeadSequence] properties: card: $ref: '#/components/schemas/AgileCard' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' indexCard: oneOf: - $ref: '#/components/schemas/CardIndexRow' - type: 'null' additionalProperties: false CreateCardRequest: type: object required: [name] properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] resolution: type: [string, 'null'] maxLength: 10000 isOpen: type: boolean default: true deadline: type: [string, 'null'] format: date-time effort: type: [integer, 'null'] minimum: 0 assigneeId: type: string format: uuid deprecated: true description: | Optional initial assignee. The server validates current Project membership and creates the Card, assignment, and both history entries in one transaction. Use `assigneeIds` for new integrations. assigneeIds: type: array maxItems: 50 uniqueItems: true items: type: string format: uuid tagIds: type: array maxItems: 50 uniqueItems: true items: type: string format: uuid cardLinks: type: array maxItems: 50 items: $ref: '#/components/schemas/CreateTeamCardLinkInput' additionalProperties: false UpdateCardRequest: type: object properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] resolution: type: [string, 'null'] maxLength: 10000 isOpen: type: boolean deadline: type: [string, 'null'] format: date-time effort: type: [integer, 'null'] minimum: 0 expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AgileCardTag: type: object required: [id, name, description, color, status, project_id] properties: &AgileCardTagProperties id: type: string format: uuid name: type: string description: type: [string, 'null'] color: type: string status: type: string project_id: type: string format: uuid additionalProperties: true AgileCardTagWithCount: type: object required: [id, name, description, color, status, project_id, card_count] properties: <<: *AgileCardTagProperties card_count: type: integer minimum: 0 additionalProperties: true CardTagResponse: type: object required: [tag] properties: tag: $ref: '#/components/schemas/AgileCardTag' additionalProperties: false CardTagsResponse: type: object required: [tags, historyHeadId, historyHeadSequence] properties: tags: type: array items: $ref: '#/components/schemas/AgileCardTag' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' indexCard: oneOf: - $ref: '#/components/schemas/CardIndexRow' - type: 'null' additionalProperties: false CardTagCatalogResponse: type: object required: [tags] properties: tags: type: array items: $ref: '#/components/schemas/AgileCardTagWithCount' additionalProperties: false CreateCardTagRequest: type: object required: [name] properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. color: type: string default: '#FF9900' description: Defaults to the Task Card tag color `#FF9900` when omitted. description: type: [string, 'null'] additionalProperties: false UpdateCardTagRequest: type: object properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. color: type: string description: type: [string, 'null'] status: type: string additionalProperties: false OffsetPageMeta: type: object required: [limit, offset, hasMore] properties: limit: type: integer minimum: 1 offset: type: integer minimum: 0 hasMore: type: boolean total: type: integer minimum: 0 additionalProperties: false CardSearchPageMeta: type: object required: - limit - hasMore - state - sort - previousCursor - nextCursor properties: limit: type: integer minimum: 1 hasMore: type: boolean total: type: integer minimum: 0 state: type: string enum: [open, closed, all] sort: type: string projection: type: string enum: [full, index, mention] hydrateOpen: type: boolean pageStart: type: integer minimum: 0 pageEnd: type: integer minimum: 0 previousCursor: type: [string, 'null'] nextCursor: type: [string, 'null'] additionalProperties: false CardSearchResponse: type: object required: [cards, meta] properties: cards: type: array items: $ref: '#/components/schemas/CardSearchCard' filterOptions: $ref: '#/components/schemas/CardFilterOptions' meta: $ref: '#/components/schemas/CardSearchPageMeta' additionalProperties: false CardIndexRow: type: object required: - id - project_id - name - resolution - is_open - deadline - effort - created_at - updated_at - tag_ids - user_ids - team_ids - team_status_ids - sprint_ids - team_statuses - team_placements - history_head_id - history_head_sequence - search_text properties: id: { type: string, format: uuid } project_id: { type: string, format: uuid } name: { type: string } resolution: { type: [string, 'null'], maxLength: 10000 } is_open: { type: boolean } deadline: { type: [string, 'null'], format: date-time } effort: { type: [integer, 'null'], minimum: 0 } created_by_user: { type: [string, 'null'], format: uuid } author_display_name: type: [string, 'null'] created_at: { type: [string, 'null'], format: date-time } closed_at: { type: [string, 'null'], format: date-time } updated_at: { type: [string, 'null'], format: date-time } tag_ids: type: array items: { type: string, format: uuid } user_ids: type: array items: { type: string, format: uuid } team_ids: type: array items: { type: string, format: uuid } team_status_ids: type: array items: { type: string, format: uuid } sprint_ids: type: array items: { type: string, format: uuid } team_statuses: type: array items: $ref: '#/components/schemas/CardPlacementStatus' team_placements: type: array items: $ref: '#/components/schemas/CardPlacement' history_head_id: $ref: '#/components/schemas/NullableHistoryHeadId' history_head_sequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' search_text: type: string maxLength: 8192 additionalProperties: false CardSearchCard: type: object required: - id - name - description - resolution - created_by_user - created_at - updated_at - deadline - is_open - project_id - effort - tag_ids - user_ids - team_ids - team_status_ids - sprint_ids - team_statuses - team_placements - history_head_id - history_head_sequence properties: <<: *AgileCardProperties tag_ids: type: array items: type: string format: uuid user_ids: type: array items: type: string format: uuid team_ids: type: array items: type: string format: uuid team_status_ids: type: array items: type: string format: uuid sprint_ids: type: array items: type: string format: uuid team_statuses: type: array description: Deterministically ordered placed-team status metadata. items: $ref: '#/components/schemas/CardPlacementStatus' team_placements: type: array description: Deterministically ordered team placement filter metadata. items: $ref: '#/components/schemas/CardPlacement' history_head_id: $ref: '#/components/schemas/NullableHistoryHeadId' history_head_sequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: true CardPlacementStatus: type: object required: [team_id, status_id, status_name, status_color, sprint_id] properties: team_id: type: string format: uuid status_id: type: string format: uuid status_name: type: [string, 'null'] status_color: type: [string, 'null'] sprint_id: type: [string, 'null'] format: uuid additionalProperties: false CardPlacement: type: object required: [team_id, status_id, sprint_id] properties: team_id: type: string format: uuid status_id: type: [string, 'null'] format: uuid sprint_id: type: [string, 'null'] format: uuid additionalProperties: false CardFilterOptions: type: object required: [tags, teams, assignees, statuses, sprints] properties: tags: type: array items: $ref: '#/components/schemas/CardTagFilterOption' teams: type: array items: $ref: '#/components/schemas/CardTeamFilterOption' assignees: type: array items: $ref: '#/components/schemas/CardAssignee' statuses: type: array items: $ref: '#/components/schemas/CardStatusFilterOption' sprints: type: array items: $ref: '#/components/schemas/CardSprintFilterOption' additionalProperties: false CardFilterOptionsResponse: type: object required: [filterOptions] properties: filterOptions: $ref: '#/components/schemas/CardFilterOptions' additionalProperties: false CardTagFilterOption: type: object required: [id, name, color] properties: id: type: string format: uuid name: type: string color: type: string additionalProperties: false CardTeamFilterOption: type: object required: [id, name] properties: id: type: string format: uuid name: type: string additionalProperties: false CardAssignee: type: object required: [id, display_name] properties: id: type: string format: uuid display_name: type: [string, 'null'] additionalProperties: false CardStatusFilterOption: type: object required: [id, name, color, teamId, teamName] properties: id: type: string format: uuid name: type: string color: type: string teamId: type: string format: uuid teamName: type: string additionalProperties: false CardSprintFilterOption: type: object required: [id, name, status, teamId, teamName] properties: id: type: string format: uuid name: type: string status: type: string enum: [active, planned] teamId: type: string format: uuid teamName: type: string additionalProperties: false RelatedCardsResponse: type: object required: [cards, meta] properties: cards: type: array items: $ref: '#/components/schemas/RelatedCard' meta: $ref: '#/components/schemas/RelatedCardsMeta' additionalProperties: false RelatedCard: type: object required: [id, name, project_id, is_open, history_head_id, assignees] properties: id: type: string format: uuid name: type: string project_id: type: string format: uuid is_open: type: boolean author_display_name: type: [string, 'null'] created_at: type: [string, 'null'] format: date-time closed_at: type: [string, 'null'] format: date-time history_head_id: $ref: '#/components/schemas/NullableHistoryHeadId' assignees: type: array items: $ref: '#/components/schemas/CardAssignee' additionalProperties: false RelatedCardsMeta: type: object required: [seedCardIds, totalRelated, excludedOnTeam, truncated] properties: seedCardIds: type: array items: type: string format: uuid totalRelated: type: integer minimum: 0 excludedOnTeam: type: integer minimum: 0 truncated: type: boolean description: True when the related component exceeds the 500-card response cap. additionalProperties: false AssignableCardMembersResponse: type: object required: [members] properties: members: type: array items: $ref: '#/components/schemas/AssignableCardMember' additionalProperties: false AssignableCardMember: type: object required: [id, name] properties: id: type: string format: uuid name: type: string additionalProperties: false CardCommentRequest: type: object required: [body] properties: body: type: string minLength: 1 expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AgileCardComment: type: object required: [id, card_id, user_id, body, created_at, updated_at] properties: &AgileCardCommentProperties id: type: string format: uuid card_id: type: string format: uuid user_id: type: [string, 'null'] format: uuid body: type: string created_at: type: [string, 'null'] format: date-time updated_at: type: [string, 'null'] format: date-time additionalProperties: true CardCommentResponse: type: object required: [comment, historyHeadId, historyHeadSequence] properties: comment: $ref: '#/components/schemas/AgileCardComment' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false CardCommentDetails: type: object required: [id, card_id, user_id, body, created_at, updated_at, author_display_name] properties: <<: *AgileCardCommentProperties author_display_name: type: [string, 'null'] additionalProperties: true CardCommentsPage: type: object required: [comments, meta] properties: comments: type: array items: $ref: '#/components/schemas/CardCommentDetails' meta: $ref: '#/components/schemas/OffsetPageMeta' additionalProperties: false AddCardTagRequest: type: object required: [tagId] properties: tagId: type: string format: uuid expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false ReplaceCardTagsRequest: type: object required: [tagIds] properties: tagIds: type: array maxItems: 50 uniqueItems: true items: type: string format: uuid expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AgileCardTagLink: type: object required: [id, card_id, tag_id, created_at] properties: id: type: string format: uuid card_id: type: string format: uuid tag_id: type: string format: uuid created_at: type: [string, 'null'] format: date-time additionalProperties: false CardTagLinkResponse: type: object required: [historyHeadId, historyHeadSequence] properties: link: $ref: '#/components/schemas/AgileCardTagLink' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' indexCard: oneOf: - $ref: '#/components/schemas/CardIndexRow' - type: 'null' additionalProperties: false description: The `link` field is omitted when the identical link already existed. AddCardUserLinkRequest: type: object required: [userId] properties: userId: type: string format: uuid relationType: type: string enum: [participant] default: participant expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AgileCardUserLink: type: object required: [id, card_id, user_id, relation_type, created_at] properties: id: type: string format: uuid card_id: type: string format: uuid user_id: type: string format: uuid relation_type: type: string created_at: type: [string, 'null'] format: date-time additionalProperties: false CardUserLinkResponse: type: object required: [historyHeadId, historyHeadSequence] properties: link: $ref: '#/components/schemas/AgileCardUserLink' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' indexCard: oneOf: - $ref: '#/components/schemas/CardIndexRow' - type: 'null' additionalProperties: false description: The `link` field is omitted when the identical user relation already existed. CardUserDetailsLink: type: object required: [link_id, id, display_name, relation_type, created_at] properties: link_id: type: string format: uuid id: type: string format: uuid display_name: type: [string, 'null'] relation_type: type: string created_at: type: [string, 'null'] format: date-time additionalProperties: false CardLinkType: type: string enum: [relates_to, depends_on, dependency_of] AddCardLinkRequest: type: object required: [cardId] properties: cardId: type: string format: uuid linkType: allOf: - $ref: '#/components/schemas/CardLinkType' default: relates_to expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AgileCardLink: type: object required: [id, card_one_id, card_two_id, link_type, created_at] properties: id: type: string format: uuid card_one_id: type: string format: uuid card_two_id: type: string format: uuid link_type: type: string enum: [relates_to, depends_on] created_at: type: [string, 'null'] format: date-time additionalProperties: false CardLinkResponse: type: object required: [historyHeadId, historyHeadSequence] properties: link: $ref: '#/components/schemas/AgileCardLink' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false description: The `link` field is omitted when the identical card link already existed. CardLinkedCard: type: object required: - id - name - description - resolution - created_by_user - created_at - updated_at - deadline - is_open - project_id - effort - link_id - link_type - direction properties: <<: *AgileCardProperties link_id: type: string format: uuid link_type: type: string enum: [relates_to, depends_on] direction: type: string enum: [outgoing, incoming] additionalProperties: true AddCardObjectLinkRequest: type: object required: [objectId] properties: objectId: type: string format: uuid description: Object verified in the current Project and selected branch. linkType: type: string enum: [related] default: related expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AgileCardObjectLink: type: object required: - id - card_id - object_id - object_name - object_type - link_type - project_id - branch_name - created_at properties: id: type: string format: uuid card_id: type: string format: uuid object_id: type: string format: uuid object_name: type: string object_type: type: string link_type: type: string project_id: type: string format: uuid branch_name: type: string created_at: type: [string, 'null'] format: date-time additionalProperties: false CardObjectLinkResponse: type: object required: [link, historyHeadId, historyHeadSequence] properties: link: $ref: '#/components/schemas/AgileCardObjectLink' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false AgileHistoryEvent: type: object required: - id - project_id - org_id - team_id - timestamp - sequence - entity_id - entity_type - user_id - event_type - event_data - author_display_name properties: id: type: string format: uuid project_id: type: [string, 'null'] format: uuid org_id: type: [string, 'null'] format: uuid team_id: type: [string, 'null'] format: uuid timestamp: type: [string, 'null'] format: date-time sequence: $ref: '#/components/schemas/HistoryHeadSequence' entity_id: type: string format: uuid entity_type: type: string enum: [card, sprint, team, status] user_id: type: [string, 'null'] format: uuid event_type: type: string enum: - created - deleted - opened - closed - ownership_transfer_requested - ownership_transfer_declined - ownership_transferred - field_updated - status_changed - sprint_added - sprint_removed - team_added - team_removed - card_added - card_removed - tag_added - tag_removed - user_link_added - user_link_removed - reference_added - reference_removed - card_link_added - card_link_removed - card_mentioned - comment_added - comment_updated - comment_deleted event_data: type: object description: For `field_updated`, `field` may be `resolution` and `old`/`new` carry the Markdown values. additionalProperties: true author_display_name: type: [string, 'null'] additionalProperties: false CardHistoryPage: type: object required: [history, meta] properties: history: type: array items: $ref: '#/components/schemas/AgileHistoryEvent' meta: $ref: '#/components/schemas/CardHistoryPageMeta' additionalProperties: false CardHistoryPageMeta: type: object required: - limit - offset - hasMore - historyHeadId - historyHeadSequence properties: limit: type: integer minimum: 1 offset: type: integer minimum: 0 hasMore: type: boolean historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false CardHistoryContext: type: object required: [users, tags, cards, references] properties: users: type: object additionalProperties: $ref: '#/components/schemas/CardHistoryUser' tags: type: object additionalProperties: $ref: '#/components/schemas/AgileCardTag' cards: type: object additionalProperties: $ref: '#/components/schemas/AgileCard' references: type: object additionalProperties: $ref: '#/components/schemas/AgileCardObjectLink' additionalProperties: false CardHistoryUser: type: object required: [id, name] properties: id: type: string format: uuid name: type: string additionalProperties: false CardDetails: type: object required: - card - tags - userLinks - linkedCards - objectLinks - teams - teamPlacementCount - comments - history - historyHeadId - historyHeadSequence - historyContext - teamOptions properties: card: $ref: '#/components/schemas/AgileCard' tags: type: array items: $ref: '#/components/schemas/AgileCardTag' userLinks: type: array items: $ref: '#/components/schemas/CardUserDetailsLink' linkedCards: type: array items: $ref: '#/components/schemas/CardLinkedCard' objectLinks: type: array items: $ref: '#/components/schemas/AgileCardObjectLink' teams: type: array items: $ref: '#/components/schemas/CardTeamPlacement' teamPlacementCount: type: integer minimum: 0 description: Number of team placements; closing State remains global and does not move any placement. comments: type: array items: $ref: '#/components/schemas/CardCommentDetails' history: type: array maxItems: 50 items: $ref: '#/components/schemas/AgileHistoryEvent' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' historyContext: $ref: '#/components/schemas/CardHistoryContext' teamOptions: type: array items: $ref: '#/components/schemas/CardTeamOption' additionalProperties: false CardTeamOption: type: object required: [id, name, organizationId, organizationName, statuses, sprints, isPlaced] properties: id: type: string format: uuid name: type: string organizationId: type: string format: uuid organizationName: type: [string, 'null'] statuses: type: array items: $ref: '#/components/schemas/CardTeamOptionStatus' sprints: type: array items: $ref: '#/components/schemas/CardTeamOptionSprint' isPlaced: type: boolean additionalProperties: false CardTeamOptionStatus: type: object required: [id, name, description, color, transitionState, closeMode, assignMoverOnEntry, requiredCardFields] properties: id: type: string format: uuid name: type: string description: type: [string, 'null'] color: type: string transitionState: $ref: '#/components/schemas/TeamTransitionState' closeMode: $ref: '#/components/schemas/TeamStatusCloseMode' assignMoverOnEntry: type: boolean description: | When true, entering this status adds the authenticated mover as an assignee without removing existing assignees. requiredCardFields: $ref: '#/components/schemas/CardRequiredFields' additionalProperties: false CardTeamOptionSprint: type: object required: [id, name, status, startDate, endDate] properties: id: type: string format: uuid name: type: string status: $ref: '#/components/schemas/TeamSprintStatus' startDate: type: [string, 'null'] format: date-time endDate: type: [string, 'null'] format: date-time additionalProperties: false TeamVisibility: type: string enum: [private, internal] AgileTeam: type: object required: [id, name, description, status, created_at, updated_at, organization_id, visibility] properties: &AgileTeamProperties id: type: string format: uuid name: type: string description: type: [string, 'null'] status: type: string description: Team lifecycle status; `active` is the database default. created_at: type: [string, 'null'] format: date-time updated_at: type: [string, 'null'] format: date-time organization_id: type: string format: uuid visibility: $ref: '#/components/schemas/TeamVisibility' additionalProperties: true TeamsResponse: type: object required: [teams] properties: teams: type: array items: $ref: '#/components/schemas/AgileTeam' additionalProperties: false TeamResponse: type: object required: [team] properties: team: $ref: '#/components/schemas/AgileTeam' additionalProperties: false GetTeamResponse: type: object required: [team, viewerCapabilities] properties: team: $ref: '#/components/schemas/AgileTeam' viewerCapabilities: $ref: '#/components/schemas/TeamViewerCapabilities' additionalProperties: false CreateTeamRequest: type: object required: [name] properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] visibility: allOf: - $ref: '#/components/schemas/TeamVisibility' default: private additionalProperties: false UpdateTeamRequest: type: object properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] status: type: string visibility: $ref: '#/components/schemas/TeamVisibility' additionalProperties: false CardTeamPlacement: type: object required: - id - name - sprint_id - status_id - sprint_name - status_name - requiredCardFields - requiredFieldsCompliant - missingRequiredFields - placementAccess properties: <<: *AgileTeamProperties sprint_id: type: [string, 'null'] format: uuid status_id: type: [string, 'null'] format: uuid sprint_name: type: [string, 'null'] status_name: type: [string, 'null'] status_color: type: [string, 'null'] status_close_mode: oneOf: - $ref: '#/components/schemas/TeamStatusCloseMode' - type: 'null' status_assign_mover_on_entry: type: [boolean, 'null'] requiredCardFields: $ref: '#/components/schemas/CardRequiredFields' requiredFieldsCompliant: type: boolean missingRequiredFields: $ref: '#/components/schemas/CardRequiredFields' org_handle: type: [string, 'null'] org_slug: type: [string, 'null'] placementAccess: type: string enum: [full, summary] description: | `summary` exposes only bounded Team, status, and sprint identifiers and labels when the Project Card reader cannot otherwise read the Team. additionalProperties: true TeamTransitionState: type: string enum: [not_started, started, closed] TeamStatusCloseMode: type: string enum: ['off', manual, automatic, add_mover_to_assignees] description: | Automatic close-on-entry behavior for a workflow status. The bulk close action is available for every status. `off` leaves card state unchanged on entry, while `automatic` closes open cards on entry. `manual` is a deprecated legacy value with the same entry behavior as `off`. `add_mover_to_assignees` is a deprecated write alias that stores `closeMode=off` with `assignMoverOnEntry=true`; reads never return that alias. CardRequiredField: type: string enum: [name, description, resolution, deadline, effort] description: User-editable scalar card field that a workflow status may require. CardRequiredFields: type: array uniqueItems: true items: $ref: '#/components/schemas/CardRequiredField' TeamWorkflowStatus: type: object required: [id, name, description, position, color, status, transition_state, closeMode, assignMoverOnEntry, requiredCardFields, team_id] properties: id: type: string format: uuid name: type: string description: type: [string, 'null'] position: type: string color: type: string status: type: string description: Workflow-status lifecycle flag; `active` is the database default. transition_state: $ref: '#/components/schemas/TeamTransitionState' closeMode: $ref: '#/components/schemas/TeamStatusCloseMode' assignMoverOnEntry: type: boolean description: | When true, entering this status adds the authenticated mover as an assignee without removing existing assignees. Combines with any `closeMode`. requiredCardFields: $ref: '#/components/schemas/CardRequiredFields' team_id: type: string format: uuid additionalProperties: false TeamStatusesResponse: type: object required: [statuses] properties: statuses: type: array items: $ref: '#/components/schemas/TeamWorkflowStatus' additionalProperties: false TeamStatusResponse: type: object required: [status] properties: status: $ref: '#/components/schemas/TeamWorkflowStatus' additionalProperties: false CreateTeamStatusRequest: type: object required: [name] properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] color: type: string default: '#000000' position: type: string transitionState: allOf: - $ref: '#/components/schemas/TeamTransitionState' default: not_started closeMode: allOf: - $ref: '#/components/schemas/TeamStatusCloseMode' default: off assignMoverOnEntry: type: boolean default: false requiredCardFields: $ref: '#/components/schemas/CardRequiredFields' additionalProperties: false UpdateTeamStatusRequest: type: object properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] color: type: string position: type: string transitionState: $ref: '#/components/schemas/TeamTransitionState' closeMode: $ref: '#/components/schemas/TeamStatusCloseMode' assignMoverOnEntry: type: boolean requiredCardFields: $ref: '#/components/schemas/CardRequiredFields' status: type: string additionalProperties: false DeleteTeamStatusRequest: type: object required: [moveToStatusId] properties: moveToStatusId: type: string format: uuid description: Different status on the same team that receives existing cards. bypassRequiredFields: type: boolean default: false description: Explicitly move cards that do not satisfy the destination status policy. expectedHistoryHeadIds: type: object additionalProperties: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false TeamSprintStatus: type: string enum: [planned, active, completed] SprintDateInput: type: string pattern: '^\d{4}-\d{2}-\d{2}(?:T.*)?$' description: ISO 8601 calendar date or date-time accepted for a sprint boundary. examples: - '2026-08-27' - '2026-08-27T09:00:00Z' NullableSprintDateInput: oneOf: - $ref: '#/components/schemas/SprintDateInput' - type: 'null' AgileTeamSprint: type: object required: [id, name, description, status, created_at, start_date, end_date, team_id] properties: &AgileTeamSprintProperties id: type: string format: uuid name: type: string description: type: [string, 'null'] status: $ref: '#/components/schemas/TeamSprintStatus' created_at: type: [string, 'null'] format: date-time start_date: type: [string, 'null'] format: date-time end_date: type: [string, 'null'] format: date-time team_id: type: string format: uuid additionalProperties: false CompletedTeamSprint: type: object required: [id, name, description, status, created_at, start_date, end_date, team_id, card_count] properties: <<: *AgileTeamSprintProperties card_count: type: integer minimum: 0 description: Current number of card placements retained in this completed sprint. additionalProperties: false CompletedTeamSprintsResponse: type: object required: [sprints, meta] properties: sprints: type: array items: $ref: '#/components/schemas/CompletedTeamSprint' meta: $ref: '#/components/schemas/OffsetPageMeta' additionalProperties: false TeamSprintResponse: type: object required: [sprint] properties: sprint: $ref: '#/components/schemas/AgileTeamSprint' additionalProperties: false CreateTeamSprintRequest: type: object required: [name] properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] status: type: string const: planned startDate: $ref: '#/components/schemas/NullableSprintDateInput' endDate: $ref: '#/components/schemas/NullableSprintDateInput' additionalProperties: false UpdateTeamSprintRequest: type: object properties: name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] startDate: $ref: '#/components/schemas/NullableSprintDateInput' endDate: $ref: '#/components/schemas/NullableSprintDateInput' additionalProperties: false StartTeamSprintRequest: type: object required: [startDate, endDate] properties: startDate: $ref: '#/components/schemas/SprintDateInput' endDate: $ref: '#/components/schemas/SprintDateInput' allowConcurrent: type: boolean default: false additionalProperties: false CompleteTeamSprintRequest: type: object properties: moveToSprintId: type: [string, 'null'] format: uuid default: null description: Planned sprint on the same team, or null to move unfinished cards to backlog. expectedHistoryHeadIds: type: object additionalProperties: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false AvailableTeamProjectOption: type: object required: [id, name] properties: id: type: string format: uuid name: type: string additionalProperties: false AvailableTeamCard: type: object required: - id - name - project_id - project_name - is_open - created_at - deadline - effort - history_head_id - author_display_name - assignees - tags - tag_ids - capabilities properties: id: type: string format: uuid name: type: string project_id: type: string format: uuid project_name: type: string is_open: type: boolean created_at: type: string format: date-time updated_at: type: [string, 'null'] format: date-time deadline: type: [string, 'null'] format: date-time effort: type: [integer, 'null'] minimum: 0 history_head_id: $ref: '#/components/schemas/NullableHistoryHeadId' author_display_name: type: [string, 'null'] assignees: type: array items: $ref: '#/components/schemas/CardAssignee' tags: type: array items: $ref: '#/components/schemas/CardTagFilterOption' tag_ids: type: array items: type: string format: uuid capabilities: $ref: '#/components/schemas/TeamCardCapabilities' additionalProperties: false AvailableTeamCardsResponse: type: object required: [team, cards, filterOptions, meta] properties: team: type: object required: [id, name] properties: id: type: string format: uuid name: type: string additionalProperties: false cards: type: array items: $ref: '#/components/schemas/AvailableTeamCard' filterOptions: type: object required: [projects] properties: projects: type: array items: $ref: '#/components/schemas/AvailableTeamProjectOption' additionalProperties: false meta: type: object required: [limit, total, hasMore, nextCursor] properties: limit: type: integer total: type: integer hasMore: type: boolean nextCursor: type: [string, 'null'] additionalProperties: false additionalProperties: false CreateTeamCardLinkInput: type: object required: [cardId] properties: cardId: type: string format: uuid linkType: type: string enum: [relates_to, depends_on, dependency_of] default: relates_to additionalProperties: false CreateTeamProjectCardRequest: type: object required: [projectId, name] properties: projectId: type: string format: uuid name: type: string description: Sanitized by the server to a resource name of at most 255 characters. description: type: [string, 'null'] resolution: type: [string, 'null'] maxLength: 10000 deadline: type: [string, 'null'] format: date-time effort: type: [integer, 'null'] minimum: 0 assigneeId: type: [string, 'null'] format: uuid deprecated: true description: Use `assigneeIds`. assigneeIds: type: array maxItems: 50 uniqueItems: true items: type: string format: uuid tagIds: type: array maxItems: 50 uniqueItems: true items: type: string format: uuid cardLinks: type: array maxItems: 50 items: $ref: '#/components/schemas/CreateTeamCardLinkInput' statusId: type: [string, 'null'] format: uuid description: Defaults to the Team's first not-started Status. sprintId: type: [string, 'null'] format: uuid description: Planned or active Sprint; null places the Card in the backlog. bypassRequiredFields: type: boolean default: false description: Explicitly create the card despite missing destination-status fields. additionalProperties: false CreateTeamProjectCardResponse: type: object required: [card, link, historyHeadId, historyHeadSequence] properties: card: $ref: '#/components/schemas/AgileCard' link: $ref: '#/components/schemas/TeamCardLink' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false TeamCardLink: type: object required: [id, card_id, team_id, sprint_id, status_id, created_at] properties: id: type: string format: uuid card_id: type: string format: uuid team_id: type: string format: uuid sprint_id: type: [string, 'null'] format: uuid status_id: type: [string, 'null'] format: uuid created_at: type: [string, 'null'] format: date-time additionalProperties: false TeamCardLinkResponse: type: object required: [link, historyHeadId, historyHeadSequence] properties: link: $ref: '#/components/schemas/TeamCardLink' historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false TeamViewerCapabilities: type: object required: - hasHierarchyOverride - canReadTeam - canManageTeam - canDeleteTeam - canReadMembers - canInviteMembers - canRemoveMembers - canUpdateMemberRoles - canAddProjects - canRemoveProjects - canCreateSprint - canReadSprints - canManageSprint - canDeleteSprint - canManageBoardCards - canReadAnalysis properties: hasHierarchyOverride: { type: boolean } canReadTeam: { type: boolean } canManageTeam: { type: boolean } canDeleteTeam: { type: boolean } canReadMembers: { type: boolean } canInviteMembers: { type: boolean } canRemoveMembers: { type: boolean } canUpdateMemberRoles: { type: boolean } canAddProjects: { type: boolean } canRemoveProjects: { type: boolean } canCreateSprint: { type: boolean } canReadSprints: { type: boolean } canManageSprint: { type: boolean } canDeleteSprint: { type: boolean } canManageBoardCards: { type: boolean } canReadAnalysis: { type: boolean } additionalProperties: false TeamCardCapabilities: type: object required: [canReadCards, canWriteCards, canDeleteCards] properties: canReadCards: { type: boolean } canWriteCards: { type: boolean } canDeleteCards: { type: boolean } additionalProperties: false TeamBoardCard: type: object required: - id - name - created_at - updated_at - deadline - is_open - project_id - effort - link_id - sprint_id - status_id - project_name - requiredCardFields - requiredFieldsCompliant - missingRequiredFields - cardAccess - capabilities properties: &TeamBoardCardProperties <<: *AgileCardProperties link_id: type: string format: uuid sprint_id: type: [string, 'null'] format: uuid status_id: type: [string, 'null'] format: uuid project_name: type: [string, 'null'] assignees: type: array items: $ref: '#/components/schemas/CardAssignee' tag_ids: type: array items: type: string format: uuid tags: type: array items: $ref: '#/components/schemas/CardTagFilterOption' requiredCardFields: $ref: '#/components/schemas/CardRequiredFields' requiredFieldsCompliant: type: boolean missingRequiredFields: $ref: '#/components/schemas/CardRequiredFields' cardAccess: type: string enum: [full, team-board-summary] description: | `full` includes Project Card fields. `team-board-summary` is the bounded operational projection returned when the caller may see the Team board but lacks `cards:read` for this Card's Project. capabilities: $ref: '#/components/schemas/TeamCardCapabilities' additionalProperties: true TeamBoardCardWithAssignees: type: object required: - id - name - created_at - updated_at - deadline - is_open - project_id - effort - link_id - sprint_id - status_id - project_name - assignees - requiredCardFields - requiredFieldsCompliant - missingRequiredFields - cardAccess - capabilities properties: <<: *TeamBoardCardProperties additionalProperties: true TeamCardFilterOptions: type: object required: [projects, tags, teams, assignees, statuses, sprints] properties: projects: type: array items: $ref: '#/components/schemas/AvailableTeamProjectOption' tags: type: array items: $ref: '#/components/schemas/CardTagFilterOption' teams: type: array items: $ref: '#/components/schemas/CardTeamFilterOption' assignees: type: array items: $ref: '#/components/schemas/CardAssignee' statuses: type: array items: type: object required: [id, name, color] properties: id: type: string format: uuid name: type: string color: type: string additionalProperties: false sprints: type: array items: type: object required: [id, name, status] properties: id: type: string format: uuid name: type: string status: type: string additionalProperties: false additionalProperties: false TeamCardsResponse: type: object required: [cards] properties: cards: type: array items: $ref: '#/components/schemas/TeamBoardCard' meta: $ref: '#/components/schemas/OffsetPageMeta' description: Present on API-key or explicitly paginated requests. filterOptions: $ref: '#/components/schemas/TeamCardFilterOptions' description: Present when `includeFilterOptions=true`. additionalProperties: false AddTeamCardRequest: type: object required: [cardId] properties: cardId: type: string format: uuid sprintId: type: [string, 'null'] format: uuid description: Omit to preserve an existing placement; null selects the backlog. statusId: type: [string, 'null'] format: uuid default: null description: Omit or use null to default a new placement or preserve an existing one. expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' bypassRequiredFields: type: boolean default: false description: Explicitly place the card despite missing destination-status fields. additionalProperties: false UpdateTeamCardSprintRequest: type: object properties: sprintId: type: [string, 'null'] format: uuid default: null description: Null moves the card to the backlog. expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false UpdateTeamCardStatusRequest: type: object required: [statusId] properties: statusId: type: string format: uuid cardUpdates: $ref: '#/components/schemas/StatusMoveCardUpdates' bypassRequiredFields: type: boolean default: false description: Explicitly move despite missing destination-status fields. expectedHistoryHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' additionalProperties: false StatusMoveCardUpdates: type: object description: Scalar card updates applied atomically with the status move. properties: name: type: string minLength: 1 maxLength: 255 description: type: [string, 'null'] resolution: type: [string, 'null'] maxLength: 10000 deadline: type: [string, 'null'] format: date-time effort: type: [integer, 'null'] minimum: 0 additionalProperties: false CloseTeamStatusCardsResponse: type: object required: - teamId - statusId - closeMode - closedCount - cardIds - historyHeads - truncated properties: teamId: type: string format: uuid statusId: type: string format: uuid closeMode: $ref: '#/components/schemas/TeamStatusCloseMode' closedCount: type: integer minimum: 0 cardIds: type: array maxItems: 100 items: type: string format: uuid historyHeads: type: array maxItems: 100 items: $ref: '#/components/schemas/CardHistoryHead' truncated: type: boolean additionalProperties: false CardHistoryHead: type: object required: [cardId, historyHeadId, historyHeadSequence] properties: cardId: type: string format: uuid historyHeadId: $ref: '#/components/schemas/NullableHistoryHeadId' historyHeadSequence: $ref: '#/components/schemas/NullableHistoryHeadSequence' additionalProperties: false TeamIndex: type: object required: [team, workflowStatuses, sprints, cards, viewerCapabilities] properties: &TeamIndexProperties team: $ref: '#/components/schemas/AgileTeam' workflowStatuses: type: array items: $ref: '#/components/schemas/TeamWorkflowStatus' sprints: type: array items: $ref: '#/components/schemas/AgileTeamSprint' cards: type: array items: $ref: '#/components/schemas/TeamBoardCardWithAssignees' meta: $ref: '#/components/schemas/OffsetPageMeta' description: Present on API-key or explicitly paginated requests. viewerCapabilities: $ref: '#/components/schemas/TeamViewerCapabilities' additionalProperties: true TeamOverview: type: object required: - team - workflowStatuses - sprints - cards - completedSprintTotal - meta - viewerCapabilities properties: <<: *TeamIndexProperties completedSprintTotal: type: integer minimum: 0 additionalProperties: true TeamReports: type: object required: [team, workflowStatuses, sprints, cards, viewerCapabilities, stats] properties: <<: *TeamIndexProperties stats: type: object required: [completed7d] properties: completed7d: type: integer minimum: 0 additionalProperties: false additionalProperties: true TeamSprintDetails: type: object required: [sprint, cards, workflowStatuses] properties: sprint: $ref: '#/components/schemas/AgileTeamSprint' cards: type: array items: $ref: '#/components/schemas/TeamBoardCard' workflowStatuses: type: array items: $ref: '#/components/schemas/TeamWorkflowStatus' additionalProperties: false LinkedTeamProject: type: object required: - id - name - slug - description - owner_org_id - archived - visibility - version - created_at - updated_at - linked_at properties: id: type: string format: uuid name: type: string slug: type: string description: type: [string, 'null'] owner_org_id: type: [string, 'null'] format: uuid archived: type: [boolean, 'null'] visibility: type: string enum: [private, internal, public] version: type: string created_at: type: [string, 'null'] format: date-time updated_at: type: [string, 'null'] format: date-time linked_at: type: [string, 'null'] format: date-time additionalProperties: false TeamProjectsResponse: type: object required: [projects] properties: projects: type: array items: $ref: '#/components/schemas/LinkedTeamProject' additionalProperties: false AddTeamProjectRequest: type: object required: [projectId] properties: projectId: type: string format: uuid additionalProperties: false TeamProjectLink: type: object required: [id, team_id, project_id, created_at] properties: id: type: string format: uuid team_id: type: string format: uuid project_id: type: string format: uuid created_at: type: [string, 'null'] format: date-time additionalProperties: false TeamProjectLinkResponse: type: object properties: link: $ref: '#/components/schemas/TeamProjectLink' additionalProperties: false description: The `link` field is omitted when the project was already linked. TeamSprintChart: type: object required: [chartType, sprint, unit, days, series, meta] properties: chartType: type: string enum: [burndown, burnup] sprint: type: object required: [id, name, status, startDate, endDate] properties: id: type: string format: uuid name: type: string status: $ref: '#/components/schemas/TeamSprintStatus' startDate: type: [string, 'null'] format: date-time endDate: type: [string, 'null'] format: date-time additionalProperties: false unit: type: string const: effort days: type: array items: type: string format: date series: type: object required: [actual, scope] properties: actual: type: array items: type: [number, 'null'] scope: type: array items: type: number ideal: type: array items: type: number description: Present for burndown charts only. additionalProperties: false meta: type: object required: [totalScope, completedScope, remainingScope, asOf, truncated] properties: totalScope: type: number completedScope: type: number remainingScope: type: number asOf: type: string format: date-time truncated: type: boolean description: True when the replay reached its 100,000-event safety bound. additionalProperties: false additionalProperties: false TeamVelocityChart: type: object required: [chartType, unit, sprints, meta] properties: chartType: type: string const: velocity unit: type: string const: effort sprints: type: array items: $ref: '#/components/schemas/TeamVelocitySprint' meta: type: object required: [from, to, sprintCount, truncated] properties: from: type: [string, 'null'] format: date-time to: type: [string, 'null'] format: date-time sprintCount: type: integer minimum: 0 truncated: type: boolean description: True when at least one replay query reached its event safety bound. additionalProperties: false additionalProperties: false TeamVelocitySprint: type: object required: [id, name, status, startDate, endDate, committed, completed, partial] properties: id: type: string format: uuid name: type: string status: type: string enum: [active, completed] startDate: type: [string, 'null'] format: date-time endDate: type: [string, 'null'] format: date-time committed: type: number completed: type: number partial: type: boolean additionalProperties: false TeamCumulativeFlowChart: type: object required: [chartType, days, categories, series, meta] properties: chartType: type: string const: cumulative-flow days: type: array items: type: string format: date categories: type: array minItems: 3 maxItems: 3 items: $ref: '#/components/schemas/TeamCumulativeFlowCategory' series: type: object required: [not_started, started, closed] properties: not_started: type: array items: type: integer minimum: 0 started: type: array items: type: integer minimum: 0 closed: type: array items: type: integer minimum: 0 additionalProperties: false meta: type: object required: [from, to, dayCount, totalCardsOnTeam, truncated] properties: from: type: string format: date to: type: string format: date dayCount: type: integer minimum: 0 totalCardsOnTeam: type: integer minimum: 0 truncated: type: boolean description: True when the replay reached its 100,000-event safety bound. additionalProperties: false additionalProperties: false TeamCumulativeFlowCategory: type: object required: [key, label, color] properties: key: $ref: '#/components/schemas/TeamTransitionState' label: type: string color: type: string additionalProperties: false ErrorEnvelope: description: | The error shape for every failure on this API, whether it was refused by the credential layer before reaching a domain or by the domain itself. Branch on `code`, which is stable. `message` is for a person reading a log or a dialog and may be reworded. `details` carries fields specific to one failure — a project-limit refusal reports its numbers there — and is absent when there are none. type: object required: [success, error] properties: success: type: boolean const: false error: type: object required: [code, message] properties: code: type: string message: type: string details: type: object additionalProperties: true additionalProperties: true additionalProperties: true SuccessResponse: type: object required: [success] properties: success: type: boolean additionalProperties: true CreateEvaluationRunRequest: type: object properties: name: type: string maxLength: 120 description: Human-readable sandbox name used in logs. ttlSeconds: type: integer minimum: 60 maximum: 3600 default: 900 description: Hard cleanup deadline, independent of Code execution timeout. additionalProperties: false EvaluationRun: type: object required: - runId - sourceProjectId - status - sandbox - createdAt - expiresAt - cleanup properties: runId: type: string format: uuid sourceProjectId: type: string testId: type: [string, 'null'] description: | The Test whose Results Value started the Code, when a Test did. Absent for a Code object run directly. testRunId: type: [string, 'null'] format: uuid description: The Test run that started the Code, when one did. codeExecutionId: type: string sessionId: type: string format: uuid description: Headless target session attached to the evaluation data-plane grant. status: $ref: '#/components/schemas/EvaluationRunStatus' sandbox: $ref: '#/components/schemas/EvaluationSandbox' dataPlane: $ref: '#/components/schemas/EvaluationDataPlaneAccess' evidence: $ref: '#/components/schemas/EvaluationEvidence' quality: $ref: '#/components/schemas/QualityObservation' failure: $ref: '#/components/schemas/RunFailure' cleanup: $ref: '#/components/schemas/EvaluationCleanup' createdAt: type: string format: date-time expiresAt: type: string format: date-time updatedAt: type: string format: date-time additionalProperties: true EvaluationRunStatus: type: string enum: [provisioning, ready, running, cleaning, cleaned, failed, expired] description: | `ready` means the target is pinned and its grant can be used. `failed` is an infrastructure failure, not a low quality score. `cleaned` and `expired` are terminal and carry no usable grant. EvaluationSandbox: type: object required: [projectId, branchName, ephemeral] properties: projectId: type: string description: Server-chosen target project. It is never accepted from the create body. branchName: type: string name: type: string ephemeral: type: boolean description: Always true for an evaluation-created target. deleteAfter: type: string format: date-time additionalProperties: true EvaluationDataPlaneAccess: allOf: - $ref: '#/components/schemas/DataPlaneAccess' - type: object required: [purpose] properties: purpose: type: string const: evaluation description: | Target-bound evaluation authority. Ordinary data-plane/execution grants remain denied from agent and git routes; this purpose admits only the target agent, and still denies git. additionalProperties: true EvaluationEvidence: type: object required: [capturedAt, transcript, tree, usage] properties: capturedAt: type: string format: date-time transcript: $ref: '#/components/schemas/AgentTranscript' tree: $ref: '#/components/schemas/ProjectTree' usage: $ref: '#/components/schemas/UsageResponse' seededObjectIds: type: array items: type: string artifacts: type: array items: type: object required: [name] properties: name: type: string mediaType: type: string fileId: type: string sha256: type: string pattern: '^[0-9a-f]{64}$' additionalProperties: true summary: type: object additionalProperties: true additionalProperties: true QualityObservation: type: object required: [value] properties: value: type: number description: Finite numeric observation returned to native Test evaluation criteria. unit: type: string rubric: type: string metrics: type: object additionalProperties: type: number additionalProperties: false EvaluationCleanup: type: object required: [status, requested] properties: status: type: string enum: [not_started, pending, completed, failed] requested: type: boolean requestedAt: type: string format: date-time completedAt: type: string format: date-time grantsRevoked: type: integer minimum: 0 projectDeleted: type: boolean failure: $ref: '#/components/schemas/RunFailure' additionalProperties: true CreateTestRunRequest: type: object properties: branch: type: string maxLength: 255 description: Branch containing the authored Test. Defaults to `main`. additionalProperties: false TestRun: type: object required: [runId, projectId, branchName, testId, status, createdAt] properties: runId: type: string format: uuid projectId: type: string branchName: type: string testId: type: string codeObjectId: type: string evaluationRunId: type: string format: uuid status: $ref: '#/components/schemas/TestRunStatus' observation: type: number description: Finite numeric observation committed to the Test's Results Value. unit: type: string verdict: $ref: '#/components/schemas/TestRunVerdict' evidence: type: object additionalProperties: true description: | Fixture-defined structured evidence. SYSTEM quality fixtures include transcript, final-tree, usage, and rubric summaries; callers must tolerate additional fixture-specific fields. failure: $ref: '#/components/schemas/RunFailure' createdAt: type: string format: date-time startedAt: type: string format: date-time completedAt: type: string format: date-time updatedAt: type: string format: date-time additionalProperties: true TestRunStatus: type: string enum: [queued, starting, running, evaluating, cancelling, completed, failed, cancelled, timed_out] description: | `completed`, `failed`, `cancelled`, and `timed_out` are terminal. `failed` means the Code execution or evaluation infrastructure failed; a valid low observation still completes and may resolve to a failing Test verdict. TestRunVerdict: type: object required: [name] properties: name: type: string score: type: [number, 'null'] criteriaTarget: type: string additionalProperties: true RunFailure: type: object required: [code, message, infrastructure] properties: code: type: string enum: - EVALUATION_SCOPE_MISSING - EVALUATION_AGENT_FAILED - EVALUATION_TIMEOUT - EVALUATION_EVIDENCE_MISSING - EVALUATION_OBSERVATION_INVALID - EVALUATION_CLEANUP_FAILED - CODE_EXECUTION_FAILED - TEST_CANCELLED - TEST_RUN_FAILED - TEST_RUN_TIMED_OUT message: type: string infrastructure: type: boolean description: True when no quality verdict may be inferred from this failure. details: type: object additionalProperties: true additionalProperties: true ListProjectsResponse: type: object required: [owned, shared] properties: owned: type: array items: $ref: '#/components/schemas/ProjectSummary' shared: type: array items: $ref: '#/components/schemas/ProjectSummary' additionalProperties: true ProjectSummary: allOf: - $ref: '#/components/schemas/ProjectMetadata' - type: object properties: inUse: type: boolean description: True when a Design Engine instance is currently running for this project. activeBranch: type: [string, 'null'] description: Most recently active running branch associated with the caller, or null. additionalProperties: true Branch: type: object required: [name] properties: name: type: string inUse: type: boolean additionalProperties: true GetProjectResponse: type: object required: [metadata] properties: metadata: $ref: '#/components/schemas/ProjectMetadata' additionalProperties: true ProjectMetadata: description: | Stored project metadata. `ProjectSummary` is this plus the live `inUse` and `activeBranch` fields that only the list endpoint computes. type: object required: [id, name] properties: id: type: string name: type: string slug: type: [string, 'null'] description: type: [string, 'null'] owner: type: string description: User id or organization id that owns the project. createdBy: type: [string, 'null'] visibility: type: string version: type: string created: type: [string, 'null'] format: date-time lastModified: type: [string, 'null'] format: date-time storageUsedBytes: type: integer minimum: 0 transferState: type: [string, 'null'] collaborators: type: array items: type: string description: User ids with effective access, including access inherited from an organization. pendingCollaborators: type: array items: type: string additionalProperties: true CreateProjectRequest: type: object properties: name: type: string description: Required unless initialPrompt is supplied. initialPrompt: type: string maxLength: 4000 description: Staged as the creator's first agent message when a client connects. description: type: string orgId: type: [string, 'null'] description: Create the project under an organization instead of the calling user. visibility: type: string enum: [private, internal, public] default: private autoName: type: boolean default: false description: Derive the project name from initialPrompt. skipInitialCommit: type: boolean default: false additionalProperties: false CreateProjectResponse: type: object required: [id] properties: id: type: string projectSlug: type: [string, 'null'] ownerSlug: type: [string, 'null'] additionalProperties: true UpdateProjectRequest: type: object minProperties: 1 properties: name: type: string description: type: [string, 'null'] visibility: type: string enum: [private, internal, public] readme: type: string tags: type: array items: type: string units: type: string additionalProperties: true UpdateProjectResponse: type: object required: [metadata] properties: metadata: $ref: '#/components/schemas/ProjectMetadata' additionalProperties: true OpenProjectRequest: type: object properties: branch: type: string default: main oldProjectId: type: string description: Previously open project to close as part of switching. initialPrompt: type: string maxLength: 4000 additionalProperties: false OpenProjectResponse: type: object required: [projectId, branchName, alreadyLoaded, permissions] properties: projectId: type: string branchName: type: string alreadyLoaded: type: boolean description: True when the project was already running and this call reused the instance. metadata: $ref: '#/components/schemas/ProjectMetadata' permissions: type: array items: type: string url: type: string description: | Design Engine replica URL. Present only for browser access-token callers; omitted for API keys. serverToken: type: string description: | Project instance credential. Present only for browser access-token callers; omitted for API keys. additionalProperties: true ListBranchesResponse: type: object required: [branches] properties: branches: type: array items: $ref: '#/components/schemas/Branch' additionalProperties: true ListPackagesResponse: type: object required: [packages] properties: packages: type: array items: type: object additionalProperties: true additionalProperties: true ListFilesResponse: type: object required: [files, count] properties: files: type: array items: $ref: '#/components/schemas/ProjectFile' count: type: integer minimum: 0 additionalProperties: true ProjectFile: type: object description: | A file attached to the project, described by the reference object that owns it. Included references and Onshape-linked references are not files in this sense and are not listed. required: [objectId, name, filename, fileType, size] properties: objectId: type: string description: Id of the reference object. Pass as `fileId` to download or delete. name: type: string description: Display name of the object. filename: type: string description: | Stored name from `assets.primary.fileName`, or `{objectId}{fileType}` for a legacy snapshot. This is the `fileName` the data-plane download takes. fileType: type: string description: Extension including the leading dot. parentId: type: [string, 'null'] description: Object the reference is attached under. size: type: [integer, 'null'] minimum: 0 description: | Byte size from `assets.primary.byteSize`, or the legacy stored-file size. Null when the reference exists but no size metadata or legacy blob exists. additionalProperties: true ProjectTree: type: object description: | Flat list of project objects excluding the project object itself. New projects contain reserved `Model` and `Library` packages whose `parent` is the project id; callers must not assume a parentless node exists. required: [objectCount, tree] properties: objectCount: type: integer minimum: 0 description: Total objects in the project, including the project object itself. tree: type: array items: $ref: '#/components/schemas/TreeNode' additionalProperties: true TreeNode: type: object description: | One object, as a node. Parentage is expressed by `parent` and `childrenCount` rather than by nesting, so the array is flat and a node can be read without walking to it. required: [id, name, type] properties: id: type: string name: type: string type: type: string parent: type: [string, 'null'] childrenCount: type: integer minimum: 0 additionalProperties: true GetObjectResponse: type: object required: [object] properties: object: type: object description: | The full object, with computed values resolved. Fields vary by `type`, so only `id`, `name`, and `type` are guaranteed. required: [id, name, type] properties: id: type: string name: type: string type: type: string additionalProperties: true additionalProperties: true AddObjectsRequest: type: object required: [objects] properties: objects: type: object minProperties: 1 description: | Objects to add, keyed by the id each should take. A key is an id, so it must be a UUID — mint one per object. Ids must be unique within the project; reusing one overwrites, which is why guessable keys are not accepted. Each body is validated against the schema for its `type`. Fields differ by type, anything the type does not define is refused rather than dropped, and every field is optional except `type` — the model supplies the rest. `tags` is refused here rather than accepted and discarded: creation does not carry them. Assign them once the object exists. additionalProperties: type: object required: [type] properties: type: type: string description: | Any object type the model defines: `task`, `requirement`, `part`, `attribute`, `risk`, `test`, `package`, and the rest. A 400 for an unrecognised type lists them all in `details.validTypes`. name: type: string parent: type: string format: uuid description: Overrides `parentId` for this object. additionalProperties: true parentId: type: [string, 'null'] format: uuid description: | Parent for objects that do not name one themselves. An id, so a UUID. additionalProperties: false AddObjectsResponse: type: object required: [addedCount, objectIds] properties: addedCount: type: integer minimum: 1 objectIds: type: array items: type: string additionalProperties: true DeleteObjectResponse: type: object required: [deletedCount, deletedObjectIds] properties: deletedCount: type: integer minimum: 1 deletedObjectIds: type: array minItems: 1 items: type: string additionalProperties: true CreateBranchRequest: type: object required: [name] properties: name: type: string minLength: 1 maxLength: 200 sourceBranch: type: string description: Branch to copy from. Defaults to the `branch` query parameter, or `main`. additionalProperties: false CreateBranchResponse: type: object required: [branch, sanitized] properties: branch: type: object required: [name, sourceBranch] properties: name: type: string description: The name actually created, which is the requested one unless it was sanitized. sourceBranch: type: string commit: type: [string, 'null'] description: Commit the new branch starts from. additionalProperties: true sanitized: type: boolean description: True when the created name differs from the requested one. additionalProperties: true DeleteBranchResponse: type: object required: [deleted] properties: deleted: type: string disconnectedUsers: type: integer minimum: 0 description: Clients disconnected by a forced delete. additionalProperties: true CommitRequest: type: object required: [message] properties: message: type: string minLength: 1 author: type: object required: [name] properties: name: type: string email: type: string description: Defaults to the acting user. additionalProperties: false additionalProperties: false CommitResponse: type: object required: [commit] properties: commit: type: object required: [hash] properties: hash: type: string message: type: string author: type: [string, 'null'] timestamp: type: [string, 'null'] format: date-time branch: type: string stats: type: [object, 'null'] properties: additions: type: integer modifications: type: integer deletions: type: integer additionalProperties: true additionalProperties: true additionalProperties: true ChangesResponse: type: object description: | Uncommitted changes on a branch, as object ids. One shape regardless of whether the branch is loaded — the answer comes from memory when it is and from a git diff when it is not, and the difference is not published. required: [hasChanges, totalObjectChanges, added, modified, deleted, deletedObjects] properties: hasChanges: type: boolean committedHash: type: [string, 'null'] description: Commit the changes are measured against. totalObjectChanges: type: integer minimum: 0 added: type: array items: type: string modified: type: array items: type: string deleted: type: array items: type: string deletedObjects: type: array description: | Enough of each deleted object to name it, since it can no longer be read from the project. items: type: object required: [objectId] properties: objectId: type: string name: type: [string, 'null'] type: type: [string, 'null'] parentId: type: [string, 'null'] additionalProperties: true additionalProperties: true ObjectHistoryResponse: type: object required: [objectId, found, totalChanges, history] properties: objectId: type: string found: type: boolean description: False when no commit on this branch ever touched the object. totalChanges: type: integer minimum: 0 history: type: array description: Newest first. Commits that did not change the object are omitted. items: $ref: '#/components/schemas/ObjectHistoryEntry' additionalProperties: true ObjectHistoryEntry: type: object required: [commit, changeType] properties: commit: type: object required: [hash] properties: hash: type: string shortHash: type: string message: type: string timestamp: type: string format: date-time author: type: object properties: name: type: string email: type: string additionalProperties: true additionalProperties: true changeType: type: string enum: [created, modified, deleted] state: type: [object, 'null'] description: The object as of this commit. Null when the commit deleted it. additionalProperties: true changes: type: object description: Field-level difference from the previous commit. additionalProperties: true additionalProperties: true CreateSessionRequest: type: object properties: branch: type: [string, 'null'] description: Branch to open. Defaults to the branch in a compound project id, or `main`. scopes: type: array items: type: string enum: - projects:read - projects:write - projects:manage - sessions:manage - agent:message - webhooks:receive - usage:read description: | Narrow the grant below the key's own scopes. Omit to inherit them. Asking for a scope the key does not hold is refused rather than silently reduced. ttlSeconds: type: integer minimum: 1 maximum: 3600 default: 900 description: Grant lifetime. Capped at one hour regardless of what is requested. additionalProperties: false Session: type: object required: [sessionId, projectId, branchName, ownerId, dataPlane] properties: sessionId: type: string format: uuid projectId: type: string description: Bare project id, without the branch suffix. branchName: type: string ownerId: type: string description: | Account or organization that owns the project. Files live under the owner's storage namespace, not the caller's, which is why a shared or org-owned project needs this rather than your own user id. dataPlane: $ref: '#/components/schemas/DataPlaneAccess' agent: $ref: '#/components/schemas/AgentState' additionalProperties: true AgentState: type: object description: | What the session's agent is doing. Present on a session read, absent on create because nothing has been asked of the agent yet. required: [status] properties: status: $ref: '#/components/schemas/AgentStatus' taskId: type: [string, 'null'] description: Identifies the run. Also names the stored conversation. lastMessageId: type: [string, 'null'] description: The `messageId` of the most recent prompt the agent took. error: $ref: '#/components/schemas/AgentFailure' additionalProperties: true AgentFailure: type: object description: | Why the run failed. Present only while `status` is `failed`, so the read that tells you the run is over also tells you why — closing the session afterwards loses nothing. required: [message] properties: message: type: string description: What went wrong, as the transcript records it. category: type: [string, 'null'] description: | The model provider's error category when the failure came from the provider, such as `context_window`, `rate_limit`, or `unavailable`; otherwise null. additionalProperties: true AgentStatus: type: string description: | - `no_session` — the machine has no record of this session; it lapsed or the project restarted. Create a new one. - `project_not_running` — the session is known but its project has unloaded. - `idle` — the session is live and no run has been started. - `starting` — a run is being set up. - `running` — a run is in progress. - `paused` — a run was stopped and can be continued with a new prompt. - `completed` — the run finished. - `failed` — the run ended in an error. `agent.error` says why, as does the transcript. - `unknown` — the machine could not be reached for this field. Retry; anything else in the same response is still valid. `paused`, `completed`, and `failed` are terminal for a run. enum: - no_session - project_not_running - idle - starting - running - paused - completed - failed - unknown SendAgentMessageRequest: type: object required: [message] properties: message: type: string minLength: 1 maxLength: 100000 description: What you want the agent to do. messageId: type: string description: | Your own id for this prompt, echoed back and recorded in the transcript. Generated for you if omitted. context: type: object description: | Opaque data kept with the session and returned to your webhook alongside the agent's replies. Davinci does not interpret it. additionalProperties: true model: type: string minLength: 1 maxLength: 200 pattern: '^[a-z0-9][a-z0-9._:-]*$' description: | A model key returned by `listAgentModels`. Omit it to use the calling account's default model. The choice applies to this prompt; every prompt that omits it uses the account default. modelOptions: type: object maxProperties: 32 description: | Model configuration keyed by the option keys returned for the selected model by `listAgentModels`. Values may be strings, numbers, or booleans. Omitted options use that model's effective account defaults. additionalProperties: $ref: '#/components/schemas/AgentModelOptionValue' webSearch: type: boolean default: false description: Whether the agent may use web search for this prompt. persona: type: string maxLength: 200 description: | The id of a persona the project defines, which sets who the agent is for this prompt and every one after it in the session. Omit to keep whichever persona the session is already running under; omitting it on the first prompt uses the project's default. This is an id, not a persona. An object is refused with `INVALID_PERSONA`, because a persona's name, purpose and approach are written into the system prompt — accepting one here would let a caller rewrite the instructions that decide what the agent will refuse to do. Define personas in the project, then name one. An id the project does not define is refused with `UNKNOWN_PERSONA` rather than quietly falling back to a default. additionalProperties: false AgentModelOptionValue: description: A typed model option value. oneOf: - type: string - type: number - type: boolean AgentModelOptionChoice: type: object required: [value, label, description] properties: value: $ref: '#/components/schemas/AgentModelOptionValue' label: type: string description: type: [string, 'null'] additionalProperties: false AgentModelOption: type: object required: [key, label, description, type, defaultValue] properties: key: type: string description: Key to use in `SendAgentMessageRequest.modelOptions`. label: type: string description: type: [string, 'null'] type: type: string enum: [enum, boolean] defaultValue: $ref: '#/components/schemas/AgentModelOptionValue' choices: type: array description: Allowed values for an `enum` option. items: $ref: '#/components/schemas/AgentModelOptionChoice' trueLabel: type: string description: Display label for `true` on a boolean option. falseLabel: type: string description: Display label for `false` on a boolean option. additionalProperties: false AgentModel: type: object required: [key, name, isDefault, options] properties: key: type: string description: Stable selector key accepted by `SendAgentMessageRequest.model`. name: type: string description: Human-readable model name. isDefault: type: boolean description: Whether this is the account profile's default chat model. options: type: array description: Effective model controls and defaults available to this account. items: $ref: '#/components/schemas/AgentModelOption' additionalProperties: false ListAgentModelsResponse: type: object required: [defaultModel, models] properties: defaultModel: type: string description: Key used when an agent message omits `model`. models: type: array items: $ref: '#/components/schemas/AgentModel' additionalProperties: false SendAgentMessageResponse: type: object required: [sessionId, taskId, messageId, status] properties: sessionId: type: string format: uuid taskId: type: string description: The run the prompt joined. messageId: type: string status: type: string description: Always `message_delivered` — a refusal is a `409`, not a status here. additionalProperties: true AgentTranscript: type: object required: [sessionId, taskId, source, status, entryCount, messages] properties: sessionId: type: string format: uuid taskId: type: string source: type: string enum: [live, persisted, none] description: | Where the answer came from. `live` is current; `persisted` is the copy saved when a run ended, and so lags a run in progress. status: $ref: '#/components/schemas/AgentStatus' entryCount: type: integer minimum: 0 description: Entries in the whole conversation, not just the returned window. messages: type: array items: $ref: '#/components/schemas/AgentMessage' description: Oldest first. Bounded by `limit`, taken from the end. additionalProperties: true AgentMessage: type: object required: [index, role, kind] properties: index: type: integer minimum: 0 description: Position in the whole conversation, so a window can be placed. role: type: string enum: [user, agent] kind: type: string description: | `text` for what was said, `thought` for the agent's reasoning, `tool` for a tool it used, `error` for a failure it hit. Treat an unrecognized value as informational rather than as a problem — new kinds can appear. text: type: string description: The content. For a `tool` entry, the tool's name. timestamp: type: [integer, 'null'] description: Milliseconds since the epoch. messageId: type: string description: Present on your own prompts, matching what you sent. tool: $ref: '#/components/schemas/AgentToolUse' additionalProperties: true AgentToolUse: type: object description: Present only on entries whose `kind` is `tool`. properties: name: type: [string, 'null'] status: type: [string, 'null'] description: | `working` while it runs, `complete` when it succeeded, otherwise the severity of what went wrong. params: description: The arguments the agent chose. Null when the tool takes none. result: description: What the tool returned. Shape is the tool's own. error: type: string description: Present when the tool failed. additionalProperties: true StopAgentResponse: type: object required: [sessionId, taskId, stopped, status] properties: sessionId: type: string format: uuid taskId: type: string stopped: type: boolean description: | False when there was no run to stop, which is not a failure — you asked for a state you already had. status: $ref: '#/components/schemas/AgentStatus' additionalProperties: true InvokeToolRequest: type: object required: [toolbox, tool] properties: toolbox: type: string maxLength: 200 description: Toolbox holding the tool, for example `Core`. tool: type: string maxLength: 200 params: type: object description: Arguments for the tool. Validated by the tool, not here. additionalProperties: true additionalProperties: false InvokeToolResponse: type: object required: [sessionId, toolbox, tool, isError, content] properties: sessionId: type: string format: uuid toolbox: type: string tool: type: string isError: type: boolean description: | Always false here — a tool that reported an error is answered as `422`, so a `200` means the tool succeeded. content: $ref: '#/components/schemas/ToolResultContent' structuredContent: type: object description: Present when the tool returns structured output as well as text. additionalProperties: true additionalProperties: true ToolResultContent: type: object required: [text, parts] properties: text: type: string description: Every text part the tool returned, joined by newlines. parts: type: array items: type: object additionalProperties: true description: | Non-text parts, such as images, passed through with their `type` intact. additionalProperties: true UsageResponse: type: object required: [scope, asOf, totals] properties: scope: type: string enum: [account, project, session] description: What the numbers cover, determined by the path you called. projectId: type: string description: Present on the project and session reads. Always the bare id. sessionId: type: string format: uuid description: Present on the session read. asOf: type: [string, 'null'] format: date-time description: | When the newest counted event was recorded, or null when the scope holds none. This is the honest bound on freshness: the engine reports usage on an interval, so a run's last few seconds may not be included. Null means "nothing here", not "nothing yet" — a scope with no usage looks the same either way, and inventing a timestamp would hide that. totals: $ref: '#/components/schemas/UsageTotals' groupBy: type: string enum: [model, project, session, day] description: Echoed back when you asked for a breakdown. groups: type: array description: | One entry per group, largest spend first — except `day`, which is chronological. Absent unless you passed `groupBy`. items: $ref: '#/components/schemas/UsageGroup' additionalProperties: true UsageTotals: type: object required: [amountUsd, promptTokens, completionTokens, reasoningTokens, cacheWriteTokens, cacheReadTokens, eventCount] properties: amountUsd: type: number description: Dollars charged (USD), to six decimal places. promptTokens: type: integer completionTokens: type: integer reasoningTokens: type: integer description: Thinking tokens, charged at the completion rate. cacheWriteTokens: type: integer cacheReadTokens: type: integer eventCount: type: integer description: | Charged calls counted. Not all of them are token-priced — image generation and web search are charged per call, so a non-zero `amountUsd` with zero tokens is normal rather than a gap. additionalProperties: true UsageGroup: allOf: - $ref: '#/components/schemas/UsageTotals' - type: object description: | Totals for one group. Which identifying field is present depends on `groupBy`, and any of them may be null — usage with no project, for example naming a new project, is real usage that belongs to no project. properties: provider: type: [string, 'null'] description: Present when grouping by model. model: type: [string, 'null'] description: Present when grouping by model. projectId: type: [string, 'null'] description: Present when grouping by project. sessionId: type: [string, 'null'] description: Present when grouping by session. day: type: [string, 'null'] format: date-time description: Midnight UTC of the day. Present when grouping by day. additionalProperties: true DataPlaneAccess: type: object description: | Everything needed to address the data plane: where to send, what to send with, and the path parameters that are not obvious from the project id alone. required: [url, token, expiresAt, connectionId, ownerId, userId, projectKey, operations] properties: url: type: string format: uri description: | Base URL for data-plane operations. Names no specific machine, so it stays valid if the project moves. token: type: string description: | The grant, `dav_gr_…`. Returned only here and only once — it is not stored in recoverable form, so a lost grant is replaced by refreshing the session rather than looked up. expiresAt: type: string format: date-time connectionId: type: string description: Pass as the `connectionId` path parameter on upload. ownerId: type: string description: Pass as the `ownerId` path parameter. userId: type: string description: Pass as the `userId` path parameter on upload. projectKey: type: string description: | Pass as the `projectId` path parameter. Compound form `{projectId}--{branchName}`, since the data plane addresses a branch. operations: type: array items: type: string description: Data-plane operations this grant authorizes. additionalProperties: true DeleteSessionResponse: type: object required: [success, sessionId] properties: success: type: boolean sessionId: type: string format: uuid revokedGrants: type: integer minimum: 0 description: How many live grants the close revoked. additionalProperties: true UploadFileRequest: type: object required: [file] properties: file: type: string format: binary objectName: type: string description: Display name for the created object. Defaults to the filename. keepAsArchive: type: boolean default: false description: | Preserve a ZIP or 7z upload as one archive reference instead of extracting it immediately. Set this when the archive will be passed to `session.extract_archive()` later. # Closed deliberately. Other engine form fields used for progress tracking # and import options remain outside the published contract. additionalProperties: false UploadFileResponse: type: object description: | The objects the upload created, keyed by id. One file does not always mean one object. A STEP assembly becomes a tree, a PDF becomes a document plus a page image per page, and a source file becomes a code object — so the answer is a map rather than a single record. A plain file that needs no conversion yields exactly one entry. required: [object] properties: object: type: object additionalProperties: $ref: '#/components/schemas/UploadedObject' additionalProperties: true UploadedObject: type: object description: | One object in the parts tree. Fields beyond these vary by `type`, so treat this as the shape you can rely on rather than the whole record. required: [id, name, type] properties: id: type: string format: uuid name: type: string type: type: string description: | What the file became: `reference` for a stored file, `geometry` or `assembly` for imported CAD, `code` for an imported source file. parent: type: string description: Id of the object this was attached under. children: type: array items: type: string fileType: type: string description: | Extension of the stored blob, including the leading dot. Present on objects that own a file. Concatenated with `id` this gives the `fileName` that downloads it. fileSize: type: integer minimum: 0 additionalProperties: true