Skip to main content
An app is org-level: it belongs to the organization, not to an agent, and outlives any session. Nineteen methods: fourteen on an app itself, plus installs.apply / installs.list / installs.update / installs.context for the declaration a project is applied from and what its crew knows, and artifacts.list for the catalog it is applied out of. API detail: Apps.

create

POST /v1/apps. AppCreate is { name, description?, type?, mcp? } — type is "frontend_only" (default) or "fullstack"; mcp is the path of the MCP endpoint a fullstack app serves ("/mcp"), refused on frontend_only. Idempotent on the name.

list

GET /v1/apps, cursor-paginated.

get

GET /v1/apps/{id}. A fullstack app’s backend advances on read — poll here until status is terminal.

update

PATCH /v1/apps/{id}. AppPatch is { description?: string | null, mcp?: string | null }. Setting mcp mints the app’s VETTA_MCP_TOKEN secret and connects every agent that can access the app to its tools as <app>.<tool>; null removes both. See Tools from your apps.

delete

DELETE /v1/apps/{id}. Tears down the hosting project and, for fullstack, the app database. Irreversible.

deploy

POST /v1/apps/{id}/deployments. files maps paths to base64 contents; the build runs asynchronously.

deployments

GET /v1/apps/{id}/deployments. Non-terminal builds advance on read.

setSecret

POST /v1/apps/{id}/secrets. Write-only: the value never comes back on any read. Overwrites an existing name.

secrets

GET /v1/apps/{id}/secrets — names and timestamps only, never values.

deleteSecret

DELETE /v1/apps/{id}/secrets/{name}.

connectDomain

POST /v1/apps/{id}/domains. The domain must already exist at client.domains; connecting is pointing, never registering.

domains

GET /v1/apps/{id}/domains.

disconnectDomain

DELETE /v1/apps/{id}/domains/{domain} — by domain name.

query

POST /v1/apps/{id}/db/query. fullstack apps only; a frontend_only app answers feature_not_configured. The database as a whole — tables, a REST facade over them, migrations, and this same query without naming the app — is client.database.

installs.apply

POST /v1/blueprints/installs. Records one applied declaration for a project — with what, by whom, and against which revision — and, when you name a published pair instead of sending one, performs the apply too. Sending a declaration records only, and that is the right shape for this client: you reconciled it yourself, which is the upsert-by-name every other method here performs, so report comes back null. Omitting the declaration and naming a published blueprint and template asks the server to reconcile the catalog’s bytes for you, as you, and report is what that run did — one line per resource, refusals included. expected_revision is expected_version copied: omit it for a deliberate unconditional apply, or send the revision you believe you are moving from and a mismatch is refused revision_conflict, whose message names the paths at which the stored declaration and yours disagree. selection: { agents: string[]; apps: string[] } names which of the template’s crew this apply provisions; omit it and the whole crew is. A deselected agent is not created, its schedules are not armed and its intake does not open; one that already exists is left running, and the report names it under deselected — apart from skipped, because a choice is not a failure. A selection that leaves out a required agent or app is refused validation_failed, naming every missing one. The install stores the selection it was applied with (null for everything, and for every install written before the field existed). See Templates.

installs.list

GET /v1/blueprints/installs. Every install in the organization, most recently applied first; project narrows it to one project’s.

installs.update

PATCH /v1/blueprints/installs/{id}. Rewrites the setup answers of an applied install — the whole map, not a merge, so send every answer you mean to keep. Each key must be a question the install’s artifact declares, and each value a string or a list of strings; anything else is refused validation_failed. The install’s context_updated_at moves and its revision does not: an answer edit is not an apply, re-provisions nothing and briefs no agent again. The crew reads the new answer through installs.context the next time it looks.

installs.context

GET /v1/blueprints/installs/{id}/context. What the crew of this install knows about the business: { object: "project_context", project, blueprint, template, artifact_version, answers: { key, label, value }[], apps: { name, url }[], agents: { name, role }[], updated_at }, derived from the install and its report — the answers as the artifact’s questions label them, the apps with the URL each is served at, the agents with the role each was declared with. It is the same object a template agent reads through its built-in project_context tool.

artifacts.list

GET /v1/blueprints/artifacts. The published catalog, newest release first — every blueprint × template that can be run, carrying the setup questions to ask first, the crew and the apps it provisions, and the timers it runs. The catalog belongs to no organization: it is the same list for everybody, and nothing a customer writes reaches it. Applying one of these rows sends its blueprint and template in place of a declaration, which the catalog holds server-side.