# Apps

List the apps installed in the workspace and what workers may do in each, and install an app by its address.

An app is a service a worker can use, such as a calendar, a mail account or a tool of your own. A person connects an app in the Little Worker app, signs in to it, and sets what workers may do in it: Read for the tools that only look, and Act for the tools that change things.

These routes list the apps in your workspace and install one by its address. Signing in to an app by hand, and changing its Read and Act levels, are a person's to do in the app. No route here does either, and no answer shows a sign-in. [Apps](/concepts/apps) explains Read and Act, how a worker gets an app, and apps on a private network.

> [!NOTE]
> A new app reaches no worker on its own. A person chooses the workers for it in the app, or a worker's `apps` list names the app. An app is an MCP server in Claude Managed Agents.

## The app object

Both routes on this page answer an app, or a list of them.

- `type` (string): Always `app`.

- `id` (app id): The app's id: `app_` and a whole number, such as `app_12`.

- `name` (string): The app's name.

- `url` (string, or null): The address of the app's server in its plain form: a lowercase scheme and host, no default port, no trailing slash, and less any query, which may hold a key the app was installed with. `null` when the app has no web address.

- `connected` (boolean): Whether Little Worker holds a sign-in for the app: a person signed in to it, or an app sign-in or fixed token for its address is saved in the workspace's shared [password set](/api/password-sets). The sign-in itself never shows.

- `read` (string): Whether workers may use the app's tools that only read: `on` lets them, `off` does not. One of `on`, `off`.

- `act` (string): What workers may do in the app that changes things: `allow` lets them act without asking, `ask` asks a person first (see [Approvals](/concepts/approvals)), and `off` never lets them act. Under `allow`, a step that sends, pays, posts or deletes still asks. One of `allow`, `ask`, `off`.

```json
{
  "type": "app",
  "id": "app_12",
  "name": "Acme CRM",
  "url": "https://crm.example.com/mcp",
  "connected": true,
  "read": "on",
  "act": "ask"
}
```

## List apps

`GET /apps`

List the apps installed in the key's workspace, newest first, whether or not they are `connected`. `order` and the `created_at` filters go by the time the app was added.

### Query parameters

- `limit` (integer): How many to answer, 1 to 100. The default is 20.
- `page` (string): The `next_page` of the answer before, to read the next page.
- `order` (string): `desc`, newest first (the default), or `asc`, oldest first. One of `desc`, `asc`.
- `created_at[gt]` (time): Only those made after this time, an RFC 3339 time compared to the millisecond the answer shows. `created_at[gte]`, `created_at[lt]` and `created_at[lte]` work the same way.

### Returns

A list: `data` holds the apps, and `next_page` is the `page` to send for the next ones (`null` on the last page).

### Example

```bash
curl "https://core.thelittleworker.com/api/v1/apps?limit=2" \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19"
```

```json
{
  "data": [
    {
      "type": "app",
      "id": "app_13",
      "name": "Price list",
      "url": "https://example.com/mcp",
      "connected": false,
      "read": "on",
      "act": "ask"
    },
    {
      "type": "app",
      "id": "app_12",
      "name": "Acme CRM",
      "url": "https://crm.example.com/mcp",
      "connected": true,
      "read": "on",
      "act": "ask"
    }
  ],
  "next_page": null
}
```

### Errors

- 400 `invalid_request_error`: A filter is not valid, such as a `limit` outside 1 to 100 (`error_code` `validation_error`). `page` is not a page this list gave with the same `order` and `created_at` filters (`error_code` `invalid_cursor`). Read the first page again.
- 401 `authentication_error`: The key is missing, removed, or not a key. Send it in `x-api-key`.
- 429 `rate_limit_error`: The workspace made too many requests this minute. Wait the seconds in `Retry-After`, then try again.

## Install an app

`POST /apps`

Install an app by the address of its server. The app starts with Read `on` and Act `ask`, and `connected` is false until the app is signed in.

The address must be an `https` address on the public internet. A user name or password in it is dropped, not kept. The host must resolve, and every address it resolves to must be public. Little Worker's servers refuse a loopback address, such as `localhost`. Little Worker running on your own computer takes one, over `http` too. An address under the domain of one of your tunnels is reached through that tunnel, and never over the public internet. An address that is already installed answers the app that is there, with its own name, so a retry is safe.

### Body

- `name` (string, required): The app's name, 1 to 80 characters. Two apps cannot share a name. The comparison ignores case and reads each run of characters other than the letters `a` to `z` and digits as one hyphen, so `Acme CRM` and `acme-crm` clash.
- `url` (string, required): The address of the app's server, 1 to 2,048 characters.

### Returns

The app.

### Example

```bash
curl "https://core.thelittleworker.com/api/v1/apps" \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{
  "name": "Price list",
  "url": "https://example.com/mcp"
}'
```

```json
{
  "type": "app",
  "id": "app_13",
  "name": "Price list",
  "url": "https://example.com/mcp",
  "connected": false,
  "read": "on",
  "act": "ask"
}
```

### Errors

- 400 `invalid_request_error`: `name` or `url` is missing, empty or too long, the body has a field the route does not take, or the address is refused (`error_code` `validation_error`). For an address, `message` says why: `An app's url must be an http or https address.` (it is no address, or has another scheme), `The connector address could not be resolved.`, `The connector address is a private network address.` (also an address under the domain of a tunnel that is not yours), `The connector address is a loopback address.` (on Little Worker's servers), or `The connector address is not HTTPS.` (an `http` address that is not loopback, or any `http` address under a tunnel domain).
- 401 `authentication_error`: The key is missing, removed, or not a key. Send it in `x-api-key`.
- 409 `conflict_error`: An app with the same name is already installed at another address (`error_code` `conflict`). Choose another name.
- 429 `rate_limit_error`: The workspace made too many requests this minute. Wait the seconds in `Retry-After`, then try again.
