# List toolboxes visible to the caller

> Source: https://elaichi.ai/docs/api-reference/toolboxes/toolbox/listtoolboxes/

`GET /toolbox`

Resource: **Toolbox** · API: **Toolboxes**

## Query parameters

- **`q`** _(string)_
  Substring match (case-insensitive) on the toolbox name. LIKE wildcards are matched literally. Max 200 characters.
- **`type`** _(string)_
  `stored` restricts the listing to ACL-backed toolboxes, omitting the dynamic `global:…`/`connection:…` rows; `automatic` is the mirror, paging the dynamic rows alone. Unset returns both, stored first. Any other value is a `400`.
  Allowed: `stored`, `automatic`
- **`connector_slug`** _(array<string>)_
  Filter to the toolboxes holding at least one tool from ANY of these connectors — a union, never an intersection. Repeat the parameter or send one comma-separated value; both are the same filter, spelled exactly as `GET /connection?connector_slug=` is. At most 25 distinct values per request; more is a `400`, never a silent truncation. A dynamic row is matched on the connectors it really spans: a `connection:{id}` row on its own connector, the `global:{user_id}` row when any of the caller's active usable connections matches. `GET /toolbox/connector` is where the values come from.

## Response body

- **`result`** _(array<object>)_
  - **`id`** _(string)_
    Toolbox id — a stored row (`tbx_…`), or a dynamic id (`global:{user_id}` / `connection:{connection_id}`).
  - **`name`** _(string)_
  - **`description`** _(string,null)_
  - **`owner_user_id`** _(string)_
    Creator (`usr_…`). For a dynamic row, the caller.
  - **`type`** _(string)_
    `stored` = a real ACL-backed row. `global`/`connection` = computed per request, always `readonly: true`.
    Allowed: `stored`, `global`, `connection`
  - **`readonly`** _(boolean)_
    True for the dynamic global/per-connection toolboxes — never editable, shareable, transferable or deletable.
  - **`template_id`** _(string,null)_
    Provenance only (stamped at creation, never a live link) — null for a from-scratch toolbox and for every dynamic row. May dangle after the template is deleted.
  - **`connection_id`** _(string)_
    Present only for `type: "connection"` dynamic rows.
  - **`connector_slug`** _(string)_
    Present only for `type: "connection"` dynamic rows.
  - **`access_level`** _(string)_
    The caller's access: `owner`, or a granted `view`/`use`/`edit` level. Always `owner` for a dynamic row. Never `oversight` — toolboxes have no org-wide oversight fallback.
  - **`owner`** _(object,null)_
    Owner summary — resolved for a row the caller does not themselves own (a toolbox shared with them), so the UI always knows whose row it is looking at. Absent for a toolbox the caller owns.
  - **`entry_count`** _(integer)_
    Omitted for dynamic rows, which have no stored entries of their own.
  - **`needs_connection_count`** _(integer)_
    Cheap per-page SQL aggregate over PROXY entries with `connection_id IS NULL` — drives the console's Status column ("Ready" / "N need connection"). Excludes synthetic entries, which pin no `connection_id` of their own by design and have no connection picker to fix. Omitted for dynamic rows (nothing to bind). Broken delegation (`delegation_ok: false`) only surfaces in detail, inside `entries[]`.
  - **`connectors`** _(object)_
    Which integrations this toolbox's tools come from, bounded — the console renders it as a stack of connector logos. Present on every `GET /toolbox` row: a stored row summarises its own entries, a `connection:{id}` row is that connection's one connector, and a `global:{user_id}` row summarises the connections it spans. Present on every command response too (`POST /toolbox`, `GET /toolbox/{id}`, `PATCH /toolbox/{id}`, `POST /toolbox/{id}/transfer`), so a client that merges one into its list does not show a just-created or just-edited toolbox as having no integrations. `total: 0` means no connector-backed tools (empty, or synthetic-only), never "not computed".
    - **`total`** _(integer)_
      Distinct connector slugs across the toolbox.
    - **`preview`** _(array<object>)_
      At most 5 connectors, ordered by entry count descending then slug ascending — the dominant integration leads and the order is stable across requests. Each entry arrives resolved: there is no follow-up `GET /connector/{slug}` to make, and a page of rows costs no per-row catalog lookup.
      - **`slug`** _(string)_
        Connector slug — connectors are keyed by slug, not by id.
      - **`name`** _(string)_
        Catalog label. Falls back to the slug when the connector no longer resolves (deleted from the catalog), so a row always has something to draw.
      - **`logo`** _(string,null)_
        The connector's square `icon` when it has one, else its wordmark `logo`, else null (the connector carries neither picture, or could not be resolved). Draw it in a square tile; render initials from `name` when it is null.
  - **`created_at`** _(string,null)_
    Null for dynamic rows, which are computed, never stored.
  - **`updated_at`** _(string,null)_
  - **`access_summary`** _(object)_
    Present on a `GET /toolbox` stored row exactly when that row's `can_see_shares` is `true` — the caller owns it, holds `edit`, or administers a team it is granted to. Absent from dynamic rows, and deliberately absent for a `view`/`use` grantee: the grantee set, counts included, is information about colleagues (docs/access-model.md §8). Read `can_see_shares` to distinguish "not permitted" from "not carried"; never infer it from this field's absence.
    - **`org_level`** _(string,null)_
      Level of the org-wide grant, or null when there is none.
      Allowed: `view`, `use`, `edit`, `null`
    - **`team_count`** _(integer)_
    - **`user_count`** _(integer)_
    - **`total`** _(integer)_
      Every grant, the org-wide one included.
    - **`preview`** _(array<object>)_
      At most 5 grantees, broadest first (org, then teams, then members), for a hover preview.
      - **`grantee_type`** _(string)_
        Allowed: `user`, `team`, `org`
      - **`grantee_id`** _(string,null)_
      - **`level`** _(string)_
        Allowed: `view`, `use`, `edit`
      - **`name`** _(string,null)_
        Display name; null for org grants and for grantees no longer in the org.
  - **`shares`** _(array<object>)_
    A bounded preview of the ACL (same cap as `access_summary`), present only on `GET /toolbox/{id}` when the caller may see the ACL. Never on a list row (`GET /toolbox`) — page `GET /toolbox/{id}/share` for the full, cursor-paginated grant list.
    - **`id`** _(string)_
      ACL entry id — the `:aclId` a `DELETE .../share/{aclId}` call takes.
    - **`resource_type`** _(string)_
      Allowed: `connection`, `toolbox`, `template`, `connector`, `file`
    - **`resource_id`** _(string)_
      The shared resource's id (a connector's slug, for that type).
    - **`grantee_type`** _(string)_
      `user` and `team` grants target one `grantee_id`; `org` applies to every member of the organization and takes no id.
      Allowed: `user`, `team`, `org`
    - **`grantee_id`** _(string,null)_
      User id (`usr_…`) or team id (`team_…`). Null for a `grantee_type: "org"` grant.
    - **`level`** _(string)_
      Same ladder for every shareable resource, low to high. `view` — see it exists, read its metadata/config; cannot exercise it. `use` — `view` + exercise it, resource-specific: run tools through a connection; execute a toolbox's tools through its bound connections (this DELEGATES — the caller runs through each entry's pinning editor's own authority, not necessarily their own); stamp a new toolbox by copying a template's entries; create connections from a connector. `edit` — `use` + change its settings, entries and its own grants.
      Allowed: `view`, `use`, `edit`
    - **`created_at`** _(string)_
    - **`updated_at`** _(string)_
  - **`connected_app_summary`** _(object)_
    The OAuth-connected apps that reach this toolbox, as a bounded rollup — present only on `GET /toolbox/{id}` for a stored toolbox, and only when the caller may see the ACL (the same gate `access_summary` uses). Never the full set: page `GET /toolbox/{id}/connected-app` for that.
    - **`count`** _(integer)_
    - **`preview`** _(array<object>)_
      At most 5 apps, for a hover preview.
      - **`grant_id`** _(string)_
        OAuth grant id (`ogrt_…`) — what `DELETE /oauth/grant/{id}` takes, scoped to the grant's own user.
      - **`client_id`** _(string)_
      - **`client_name`** _(string,null)_
        Null when the OAuth client row is gone.
      - **`user`** _(object)_
      - **`via`** _(string)_
        `toolbox`: this toolbox is named explicitly on the grant. `all_tools`: an "All my tools" authorization by a user who can currently use this toolbox — computed live, not a stored fact.
        Allowed: `toolbox`, `all_tools`
  - **`has_skill`** _(boolean)_
    Whether a skill is written. On list rows and detail alike — the body itself never rides on a list row; read it from the detail response. Omitted on a dynamic row, which has no skill of its own.
  - **`skill_may_be_stale`** _(boolean)_
    True once the entries changed after the skill was last written; cleared by the next write of `skill`. Never true without a skill. Omitted on a dynamic row.
  - **`can_use`** _(boolean)_
    Whether the caller may execute this toolbox's tools — the caller's grant-or-ownership level (§10). Present on every list and detail row for both templates and toolboxes — the two ACL-backed resource types with a `use`-gated action of their own.
  - **`can_share`** _(boolean)_
    Whether the caller may share this toolbox — owner, `edit` access, or `toolbox:share`. No `toolbox:manage` fallback. Mirrors `POST /toolbox/{id}/share`'s own check.
  - **`can_manage`** _(boolean)_
    Whether the caller may edit this toolbox's own settings — owner, or `edit` access. No `toolbox:manage` fallback. Mirrors `PATCH /toolbox/{id}`.
  - **`can_transfer`** _(boolean)_
    Whether the caller may transfer or delete this toolbox — ownership, full stop. No `toolbox:manage` fallback. Mirrors `POST /toolbox/{id}/transfer` and `DELETE /toolbox/{id}`.
  - **`can_revoke_share`** _(boolean)_
    `can_share`, verbatim — a THIRD formula, distinct from `can_manage`: an `edit` grantee whose role omits `toolbox:share` can edit the toolbox but was never meant to grant or revoke someone else's access to it. Mirrors `DELETE /toolbox/{id}/share/{aclId}`.
  - **`access_via`** _(string)_
    How the CALLER reaches this toolbox — not who else can. `owner` — they own it. `direct` — a grant naming them personally. `team` — a grant to a team they belong to (or, per §6.2, one they administer), named in `access_via_team`. `org` — an organization-wide grant. When several sources apply the BROADEST wins and the caller's access level is not consulted: owner, else `org`, else `team`, else `direct`. So a caller granted `edit` personally AND `view` org-wide reads `org` — a narrower grant must never mask org-wide exposure, since this field says how far the toolbox reaches, not what the caller may do with it. Deliberately NOT gated on `can_see_shares`, and deliberately not a widening of it: this is the caller's OWN grant and their OWN team memberships, so a `view`/`use` grantee receives it while the grantee list — information about colleagues — stays closed to them. No other member is ever named. ABSENT when nothing reaches the caller — a transfer answering the ex-owner of a resource that was never shared, or a catalog row browsed with no grant behind it. Absent means "no source to name", never "not permitted", and never an implied `org`.
    Allowed: `owner`, `direct`, `team`, `org`
  - **`access_via_team`** _(object)_
    Present exactly when `access_via` is `team`, absent otherwise. The team the caller reaches this toolbox through — one of their own teams, never a disclosure about anybody else.
    - **`id`** _(string)_
      Team id (`team_…`).
    - **`name`** _(string,null)_
      Team display name, or null when the team no longer resolves in the directory — the same null contract every resolved grantee name carries.
- **`next_cursor`** _(string,null)_
- **`prev_cursor`** _(string,null)_

## Code examples

### curl

```bash
curl -X GET 'https://api.elaichi.ai/toolbox' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json'
```

### JavaScript

```javascript
const response = await fetch('https://api.elaichi.ai/toolbox', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
    'Content-Type': 'application/json',
  },
});

const data = await response.json();
console.log(data);
```

### Python

```python
import os
import requests

url = "https://api.elaichi.ai/toolbox"
headers = {
    "Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
    "Content-Type": "application/json",
}

response = requests.get(url, headers=headers)
print(response.json())
```
