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.