> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# apps

> Hosted web applications — client.apps.

An app is **org-level**: it belongs to the organization, not to an agent, and outlives any session. Seventeen methods: fourteen on an app itself, plus `installs.apply` / `installs.list` for the declaration a project is applied from and `artifacts.list` for the catalog it is applied out of. API detail: [Apps](/docs/api/apps).

## create

```ts theme={"system"}
client.apps.create(body: AppCreate): Promise<App>
```

`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

```ts theme={"system"}
client.apps.list(query?: ListQuery): Promise<Page<App>>
```

`GET /v1/apps`, cursor-paginated.

## get

```ts theme={"system"}
client.apps.get(id: string): Promise<App>
```

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

## update

```ts theme={"system"}
client.apps.update(id: string, body: AppPatch): Promise<App>
```

`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](/docs/capabilities/tools#tools-from-your-apps).

## delete

```ts theme={"system"}
client.apps.delete(id: string): Promise<Deleted>
```

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

## deploy

```ts theme={"system"}
client.apps.deploy(id: string, files: Record<string, string>): Promise<AppDeployment>
```

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

## deployments

```ts theme={"system"}
client.apps.deployments(id: string, query?: { limit?: number }): Promise<Page<AppDeployment>>
```

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

## setSecret

```ts theme={"system"}
client.apps.setSecret(id: string, body: { name: string; value: string }): Promise<AppSecret>
```

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

## secrets

```ts theme={"system"}
client.apps.secrets(id: string): Promise<{ object: "list"; data: AppSecret[] }>
```

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

## deleteSecret

```ts theme={"system"}
client.apps.deleteSecret(id: string, name: string): Promise<{ object: "app_secret"; name: string; deleted: boolean }>
```

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

## connectDomain

```ts theme={"system"}
client.apps.connectDomain(id: string, domainId: string): Promise<AppDomain>
```

`POST /v1/apps/{id}/domains`. The domain must already exist at [`client.domains`](/docs/sdk/domains); connecting is pointing, never registering.

## domains

```ts theme={"system"}
client.apps.domains(id: string): Promise<{ object: "list"; data: AppDomain[] }>
```

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

## disconnectDomain

```ts theme={"system"}
client.apps.disconnectDomain(id: string, domain: string): Promise<{ object: "app_domain"; domain: string; deleted: boolean }>
```

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

## query

```ts theme={"system"}
client.apps.query(id: string, query: string): Promise<{ object: "app_db_result"; rows: unknown[]; row_count: number }>
```

`POST /v1/apps/{id}/db/query`. `fullstack` apps only; a `frontend_only` app answers `feature_not_configured`.

## installs.apply

```ts theme={"system"}
client.apps.installs.apply(body: InstallApply): Promise<BlueprintInstall>
```

`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`](/docs/api/agents) 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.

## installs.list

```ts theme={"system"}
client.apps.installs.list(query?: { limit?: number; after?: string }): Promise<Page<BlueprintInstall>>
```

`GET /v1/blueprints/installs`. Every install in the organization, most recently applied first.

## artifacts.list

```ts theme={"system"}
client.apps.artifacts.list(query?: {
  blueprint?: string; template?: string; limit?: number; after?: string;
}): Promise<Page<BlueprintArtifact>>
```

`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.
