# List kits

> Fetch the curated tool collections, each with its tools already resolved.

Canonical page: https://www.rundiffusion.com/docs/api/kits/list
Endpoint: GET /api/v2/kits
Authorization: OAuth device flow or Personal API Access Token or Company API Access Token

---

A kit is the tool catalog re-cut by intent and curated by hand, so a picker can
offer a shortlist instead of the whole catalog. Each kit arrives with its tools
already resolved and filtered to what the account can run, its own tab row, and
the tool to open by default.

Fetch this once when your picker opens and render straight from it. No
follow-up call to [List tools](/docs/api/tools/list) is needed to build the UI.

`GET /api/v2/kits`

Authorization: OAuth device flow or Personal API Access Token or Company API Access Token

## Request

**Headers**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | string | Yes | Bearer token. This endpoint accepts an OAuth device flow token, a Personal API Access Token, or a Company API Access Token. See [Authentication](/docs/api/authentication). |

Every parameter is optional.

**Query**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `team_id` | string | No | The team to read as. Omit it to read as your personal account. This endpoint acts on one account, so pass exactly one id. Which tools resolve inside a kit depends on what the selected account can run. |

## Response

`200 OK` with every kit you can see under `data`. This endpoint is unpaged:
there are a handful of kits and callers want all of them, so there is no
`has_more` and no cursor.

```json
{
  "data": [
    {
      "id": "image",
      "label": "Image",
      "icon": "mdi-image",
      "description": "Generate images from a prompt",
      "kit_tags": ["Featured", "Anime", "Other"],
      "default_tool_id": "Xq2b…",
      "tools": [
        {
          "tool": {
            "id": "Xq2b…",
            "name": "Flux Dev",
            "description": "High-quality text to image",
            "avatar_url": "https://rundiffusion.com/...",
            "average_gen_in_seconds": 8.4,
            "tool_tags": [
              { "id": "tg_1…", "type": "MODEL_FAMILY", "label": "Flux" }
            ],
            "pricing_type": "COST",
            "tokens_per_result": 2
          },
          "kit_tags": ["Featured"],
          "labels": [
            { "id": "label:fast", "icon": "mdi-flash", "label": "Fast" }
          ]
        }
      ]
    }
  ]
}
```

### Top level

| Name | Type | Description |
| --- | --- | --- |
| `data` | array | Every kit you can see, in display order. See [Kit object](#kit-object) below. Unpaged, so there is no cursor to follow. |

### Kit object

| Name | Type | Description |
| --- | --- | --- |
| `id` | string | Stable kit identifier, such as image, imageEdit, or 3d. Pass it as kit_id to [Get a kit](/docs/api/kits/get). Note this one id is camelCase while the rest of the API is snake_case: it is the same value the web app uses in its URL, and a second spelling would mean two names for one kit. |
| `label` | string | Display name. Show this, never the id. |
| `icon` | string | Material Design Icons name for the kit's card, such as mdi-image. Falls back to a generic shape icon when a kit has none. |
| `description` | string | One-line blurb to show under the kit name. Empty string when unset, rather than null. |
| `kit_tags` | array | The tab row for this kit, as plain strings in display order: Featured first when present, then the rest alphabetically, then Other last. Derived from the tools actually returned, so no tab renders empty. |
| `default_tool_id` | string \| null | The tool to open when the user has no stored preference. Always one of the tools below, or null when the kit has none. |
| `tools` | array | The kit's tools in curated order, which is the order to render them in. Tools this account cannot run are already removed. See [Tool entry](#tool-entry) below. |

### Tool entry

| Name | Type | Description |
| --- | --- | --- |
| `tool` | object | The tool itself, in the same shape [List tools](/docs/api/tools/list#tool-object) returns, so one renderer serves both. Resolved live from the catalog rather than stored on the kit, so a renamed tool is never stale here. |
| `kit_tags` | array | Which tabs inside this kit the tool appears under. Match these against the kit's own kit_tags to build the filter. Unrelated to tool.tool_tags, which is the catalog-wide taxonomy. |
| `labels` | array | Small badges to show on the tool's card, each { id, icon, label } and sometimes carrying value, type, or tooltip. Capability signalling only: unlike a kit tag, a label never filters. |

## Two different kinds of tag

A response carries two tag vocabularies that look alike and are not
interchangeable.

`kit_tags` are the tabs within one kit. They are editorial strings chosen by a
curator, not ids, and they only mean anything inside the kit that carries them.
Build a kit's filter by matching a tool entry's `kit_tags` against the kit's
own.

`tool.tool_tags` is the catalog-wide taxonomy, the same objects
[List tools](/docs/api/tools/list) returns, each with an `id` you can pass back
as the `tool_tag` filter. Those ids are meaningless as kit tabs, and a kit tab
string is meaningless as a catalog filter.

## What you can see

Which kits come back depends on the client you signed in from, which the server
reads from the device record written when you completed the
[device flow](/docs/api/authentication). Curation is scoped per surface, so a
plugin sees the kits curated for it. There is no parameter for this and asking
for another surface's curation is not possible.

> **A Personal or Company API Access Token sees the unscoped kits**
>
> A key is not a registered client, so it cannot be placed on a surface. Those
> callers receive only the kits that are published to every surface rather than
> a surface-specific cut. Register through the device flow if you need what a
> particular plugin sees.

A kit whose every tool is invisible to the account is dropped from the response
rather than returned empty, so a kit in `data` always opens onto something.

## Errors

| Name | Type | Description |
| --- | --- | --- |
| `401` | UNAUTHENTICATED | Missing, malformed, or expired token. |
| `403` | PLUGIN_NOT_ALLOWED | The active team has not enabled the client you are calling from, the same as every other gated endpoint. See [OAuth device flow](/docs/api/authentication#oauth-device-flow). |
| `429` | RATE_LIMITED | Too many requests. Back off and retry per the Retry-After header. See [Rate limits](/docs/api/rate-limits#kits). |

See [Errors](/docs/api/errors) for the full envelope and the code list.
