> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ada.cx/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ada.cx/_mcp/server.

# Tools API

The Tools API is a single inventory of the HTTP tools (`api`) and code tools (`code`) configured on your AI Agent. Use it to list, fetch, create, update, and delete tools through one Platform API instead of a separate API per type.

Download full OpenAPI spec

## Endpoints

* **List tools** (`GET /v2/tools/`): Returns the Agent's tools in cursor-paginated pages. See [List tools](#list-tools).
* **Get a tool** (`GET /v2/tools/{tool_id}`): Returns a single tool by its `id`, including the type-specific body. See [Get a tool](#get-a-tool).
* **Create a tool** (`POST /v2/tools/`): Creates an `api` or `code` tool. See [Create a tool](#create-a-tool).
* **Update a tool** (`PATCH /v2/tools/{tool_id}`): Partially updates a tool. Write rights depend on type. See [Update a tool](#update-a-tool).
* **Delete a tool** (`DELETE /v2/tools/{tool_id}`): Soft-deletes an `api` or `code` tool. See [Delete a tool](#delete-a-tool).

Read and write responses use the shared Tool envelope: `id`, `type`, `name`, `description`, `inputs`, `outputs`, `enabled`, `direct_use`, and `availability_rules`. Required fields that have no value are returned as `null` rather than omitted.

## Tool types

| `type` | What it is                                                                               | Type body on GET                                                                    |
| ------ | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `api`  | An HTTP tool (an [Action](/docs/automation/tools/api-tools) that calls an external API). | `api` — URL, method, headers, and body. `Authorization` headers are never returned. |
| `code` | A code tool that runs sandboxed Python.                                                  | `code` — source code and environment variables.                                     |

Code tools require the code tools product entitlement. Without it, they are omitted from the list, and `GET /v2/tools/{tool_id}` returns `404` for a code tool id. `POST` of a `code` tool also fails without the entitlement.

## Shared fields

| Field                | Type            | Description                                                                                                                                                   |
| -------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                 | string          | The tool's unique identifier.                                                                                                                                 |
| `type`               | string          | One of `api` or `code`.                                                                                                                                       |
| `name`               | string          | The tool's name, as the model sees it.                                                                                                                        |
| `description`        | string          | What the tool does, as the model sees it.                                                                                                                     |
| `inputs`             | array           | The inputs the tool declares.                                                                                                                                 |
| `outputs`            | array           | The values the tool returns.                                                                                                                                  |
| `enabled`            | boolean         | Whether the tool is available to the Agent. This is the stored per-tool toggle.                                                                               |
| `direct_use`         | boolean \| null | Whether the Agent may call this tool on its own, rather than only as a step inside a process.                                                                 |
| `availability_rules` | object \| null  | The rule that gates when the tool is offered. `null` when the tool is always available. See [Availability rules](/reference/introduction/availability-rules). |

## List tools

`GET /v2/tools/` returns `{ data, meta: { next_page_url } }`.

List items use the same Tool envelope as GET-by-id **without** the type body. There is no `api` or `code` key on a list item. HTTP details and source code belong on a single-tool fetch.

Results are returned in fixed source order: `api`, then `code`. Each source is ordered by `id`.

### Query parameters

| Parameter | Description                                                                                                |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| `type`    | Restrict the list to one tool type: `api` or `code`. Omitted sources are not queried.                      |
| `enabled` | Filter on the tool's own `enabled` flag. Same meaning for `api` and `code`: the stored per-tool toggle.    |
| `limit`   | Maximum tools per page. Integer from `1` to `100`. Default `25`. Values outside that range return `400`.   |
| `cursor`  | Opaque pagination token from a previous response's `meta.next_page_url`. Treat it as opaque, not as an id. |

### Pagination

The list is cursor-paginated. Read `meta.next_page_url` from the response and replay it unchanged to fetch the next page. `next_page_url` is `null` on the last or empty page. See [Pagination](/reference/introduction/pagination).

A cursor is bound to the Agent that minted it and to the `type` and `enabled` filters in effect. Changing those filters mid-walk, or presenting another Agent's cursor, returns `400`.

## Get a tool

`GET /v2/tools/{tool_id}` returns one tool in the unified Tool shape. Shared fields sit at the top level; everything specific to how the tool runs is nested under the key matching `type` (`api` or `code`).

* `Authorization` headers are stripped from `api.request.headers`. Other header values pass through, with variable references in `{var:<name>|<default>}` form.
* An unknown id, an id from another Agent, or a malformed id returns `404` or `400`.

## Create a tool

`POST /v2/tools/` creates an `api` or `code` tool and returns the created Tool (`201`).

* `type`, `name`, and `description` are required. `type=api` requires an `api` body with `url`. `type=code` requires a `code` body with `source_code`.
* A name that collides with a tool of the other type (`api` ↔ `code`) returns `409`. Reusing an `api` name among other `api` tools is not rejected.
* `availability_rules` is the structured Knowledge rule object, not an internal DSL string. See [Availability rules](/reference/introduction/availability-rules).
* `Authorization` headers on `api` tools are stored but stripped on every read.
* `code.environment` is optional. `source` is one of `literal`, `variable`, `secret`, or `sensitive_value`.
* `secret` takes the id of any secret-bearing variable: a sensitive variable, or a client-secret-scoped token. Which store it resolves from follows that variable's own scope.
* `variable` takes a non-sensitive variable id only. Binding a sensitive variable or a token under it returns `422`.
* If `source` is `sensitive_value`, GET returns an empty `value`. A GET-then-POST copy does not copy the stored secret. Send the value again.

## Update a tool

`PATCH /v2/tools/{tool_id}` is a merge-patch. Omitted fields are preserved. Nested objects (`api`, `code`, `api.request`) merge key-by-key. Arrays (`inputs`, `outputs`, `headers`, `environment`) **replace** when the key is present. Send the complete list, including entries that are not changing.

`availability_rules` is the one null-delete: omit it to leave the rule untouched, send an object to replace, send `null` to detach.

Sending a different `type`, or a type body that does not match the tool (`api` on a `code` tool), returns `422`. An empty `{}` body is a no-op `200`.

### Write rights by type

|                | `api`                                                                  | `code`                                 |
| -------------- | ---------------------------------------------------------------------- | -------------------------------------- |
| Control        | `enabled`, `direct_use`, `availability_rules`                          | Same                                   |
| Contract       | `name`, `description`, `inputs`, `outputs`                             | Same                                   |
| Implementation | `api.url`, `api.request` (`method`, `content_type`, `body`, `headers`) | `code.source_code`, `code.environment` |

### Inputs and outputs

GET returns `id` on every input and output. The value is `null` for `api` inputs.

`id` is the identity of an output and of a `code` input. Other entities hold that id. `api` inputs stay name-keyed.

* Send the stored `id` with a new `name` to rename an output or a `code` input.
* A rename without `id` returns `422`.
* An `api` input rename returns `422`.
* Same `name` with a new `description`, `type`, `key`, `source`, `is_visible_to_llm`, or `variable.id` updates that row.
* Adding a name while keeping existing names is allowed. Removing a name (send only what remains) is allowed.
* Dropping a stored name and adding a different name in the same PATCH returns `422`.
* If you omit `id` and keep the same `name`, the server matches by name. Redactions stay attached when `key` changes.

Inputs on this API are `id`, `name`, `type`, and `description`. Omit `id` on create. The server mints one for `code` inputs and for every output. The bound variable for an output is `variable.id`, not `variable_id`.

`required` on an input is ignored on write. GET always returns it. `api` and `code` tools return `null`.

If `headers` is omitted from an `api` PATCH, stored headers, including `Authorization`, are left in place. `Authorization` stays stripped on read-back.

If `code.environment` is present, the array replaces in full. For a `sensitive_value` row, an empty `value` leaves the stored secret unchanged. Remove the row to clear it.

A name that collides with another `api` or `code` tool returns `409`.

## Delete a tool

`DELETE /v2/tools/{tool_id}` soft-deletes an `api` or `code` tool and returns `204`.

* An `api` tool that other entities still reference returns `409`. Code tools have no dependency check.

## Authentication

Requests are authenticated with a Bearer API key. See [Authentication](/reference/introduction/authentication) for details on generating and using API keys.

API keys use the same Platform API permission as other v2 APIs. There are no per-type scopes. One key lists every tool type the Agent is entitled to.