---
title: "Create a tool revision"
method: POST
path: "/v1/tools/{tool_id}/revisions"
tags: ["tools"]
---

# Create a tool revision

`POST /v1/tools/{tool_id}/revisions`

## Path parameters

- `tool_id` string, uuid, required

## Request body

- ToolRevisionCreate
  - `name` string, required
  - `description` string, nullable
  - `based_on_revision_id` string, uuid, nullable
  - `configuration` APICallConfiguration — Configuration for an API_CALL tool, stored in Tool.configuration. Supports ``{{variable}}`` placeholders in url, headers, and body that are resolved at execution time from the tool's input variables and runtime metadata (via ``{{metadata.key}}``).
    - `url` string, required — API endpoint URL — supports {{variable}} placeholders
    - `method` 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
    - `headers` HeaderConfig[]
      - `key` string, required
      - `value` string, required
      - `secure` boolean — When true, value is stored encrypted in the database
    - `query_params` QueryParamConfig[]
      - `key` string, required
      - `value` string, required
      - `secure` boolean — When true, value is stored encrypted in the database
    - `body` object
    - `timeout` integer — Request timeout in seconds
    - `variables` VariableDefinition[]
      - `name` string, required
      - `type` 'str' | 'int' | 'float' | 'bool'
      - `description` string, nullable
      - `required` boolean
    - `retry` RetryConfig — Retry configuration — same schema at org, tool, and integration-instance level.
      - `max_retries` integer
      - `base_delay_seconds` number
      - `max_delay_seconds` number
      - `jitter` boolean
  - `transfer_target` TransferTargetInput — Operator-supplied config for a call_transfer target (ENG, voice). A transfer target carries either a static ``destination`` (E.164 or sip: URI) or a dynamic ``destination_source`` (api_tool reference that resolves the destination at transfer time). The two are mutually exclusive. ``mode`` is always ``"cold"``. ``destination`` validity (E.164 or ``sip:`` URI) is enforced at the service layer via :func:`~src.custom_tools.api._shared.transfer_target.validate_transfer_target_config` so a bad destination surfaces as a clean 422. The label / when-to-use are carried on the Tool's ``name`` / ``description``, not here.
    - `destination` string, nullable — Dial target — E.164 (e.g. +15105550100) or a sip: URI
    - `destination_source` DestinationSourceConfig — How a transfer target's destination is resolved dynamically at transfer time. The platform invokes the referenced ``api_call`` GET tool with ``input_mapping`` (values may carry ``{{context_variable}}`` placeholders), extracts ``response_path`` from the tool's response, and validates the result as an E.164 / ``sip:`` destination. The lookup is never exposed to the LLM — it is a deterministic platform lookup executed through the shared ``execute_api_call`` stack (SSRF-pinned client, KMS secret decrypt, response-field narrowing, retry). Secrets live on the referenced tool (not embedded in the transfer target).
      - `type` 'api_tool'
      - `tool_id` string, required
      - `input_mapping` object
      - `response_path` string, required
    - `mode` 'cold' | 'warm'
  - `response_schema` ResponseFieldSelector — The projection applied to a tool response.
    - `field_mappings` ResponseFieldMapping[]
      - `path` string, required — Dot-path into the response (e.g. 'data.order.id')
      - `alias` string, nullable — Output key name; defaults to the full dot-path
  - `input_defaults` object, nullable

## Response `201`

Successful Response

- ToolRevisionResponse
  - `id` string, uuid, required
  - `tool_id` string, uuid, required
  - `name` string, required
  - `description` string, nullable, required
  - `configuration` APICallConfiguration — Configuration for an API_CALL tool, stored in Tool.configuration. Supports ``{{variable}}`` placeholders in url, headers, and body that are resolved at execution time from the tool's input variables and runtime metadata (via ``{{metadata.key}}``).
    - `url` string, required — API endpoint URL — supports {{variable}} placeholders
    - `method` 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
    - `headers` HeaderConfig[]
      - `key` string, required
      - `value` string, required
      - `secure` boolean — When true, value is stored encrypted in the database
    - `query_params` QueryParamConfig[]
      - `key` string, required
      - `value` string, required
      - `secure` boolean — When true, value is stored encrypted in the database
    - `body` object
    - `timeout` integer — Request timeout in seconds
    - `variables` VariableDefinition[]
      - `name` string, required
      - `type` 'str' | 'int' | 'float' | 'bool'
      - `description` string, nullable
      - `required` boolean
    - `retry` RetryConfig — Retry configuration — same schema at org, tool, and integration-instance level.
      - `max_retries` integer
      - `base_delay_seconds` number
      - `max_delay_seconds` number
      - `jitter` boolean
  - `transfer_target` TransferTargetView — A call_transfer revision's stored target, surfaced on reads. ``ToolRevisionResponse.configuration`` is api_call-typed and parses to ``None`` for a transfer config (it has no ``url``), so this field carries the destination/mode back for the transfer-target picker. ``label`` / ``when_to_use`` come from the parent Tool's ``name`` / ``description``. Either ``destination`` (static) or ``destination_source`` (api_tool dynamic) is present, never both. The unused variant is omitted from serialization.
    - `destination` string, nullable
    - `destination_source` DestinationSourceConfig — How a transfer target's destination is resolved dynamically at transfer time. The platform invokes the referenced ``api_call`` GET tool with ``input_mapping`` (values may carry ``{{context_variable}}`` placeholders), extracts ``response_path`` from the tool's response, and validates the result as an E.164 / ``sip:`` destination. The lookup is never exposed to the LLM — it is a deterministic platform lookup executed through the shared ``execute_api_call`` stack (SSRF-pinned client, KMS secret decrypt, response-field narrowing, retry). Secrets live on the referenced tool (not embedded in the transfer target).
      - `type` 'api_tool'
      - `tool_id` string, required
      - `input_mapping` object
      - `response_path` string, required
    - `mode` 'cold' | 'warm'
  - `response_schema` ResponseFieldSelector — The projection applied to a tool response.
    - `field_mappings` ResponseFieldMapping[]
      - `path` string, required — Dot-path into the response (e.g. 'data.order.id')
      - `alias` string, nullable — Output key name; defaults to the full dot-path
  - `status` string, required
  - `has_secrets` boolean
  - `input_defaults` object, nullable
  - `compatibility` ToolCompatibilityReportResponse — Impact report shared by preflight analysis and successful promotion. Pre-prod: findings are advisory warnings — promotion always succeeds. The ``has_blocking`` / ``active_blocking_*`` fields retain their literal blocking semantics (and therefore remain false/zero today).
    - `tool_id` string, uuid, required
    - `old_revision_id` string, uuid, nullable, required
    - `new_revision_id` string, uuid, required
    - `findings` ToolCompatibilityFindingResponse[]
      - `severity` 'blocking' | 'advisory', required
      - `assistant_id` string, uuid, required
      - `assistant_revision_id` string, uuid, required
      - `revision_state` 'active' | 'candidate' | 'historical', required
      - `finding_type` string, required
      - `field_path` string, required
      - `detail` string, required
      - `configuration_scope` 'assistant_tool_default' | 'agent_node_tool' | 'action_step_tool', required
      - `workflow_id` string, uuid, nullable
      - `workflow_revision_id` string, uuid, nullable
      - `component_node_id` string, nullable
      - `graph_node_id` string, nullable
      - `graph_node_name` string, nullable
      - `step_id` string, nullable
      - `tool_ref_index` integer, nullable
    - `has_blocking` boolean, required
    - `active_blocking_count` integer, required
    - `active_blocking_finding_count` integer, required
    - `active_finding_count` integer, required
    - `affected_assistant_count` integer, required
  - `created_by` string, nullable, required
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `default_count` integer, required — How many input variables carry an operator *default* (ENG-590).
  - `pinned_count` integer, required — How many input variables are operator-*pinned* (ENG-590).
  - `stale_input_fields` string[], required — Configured variables removed/renamed/retyped by an operator edit.
  - `merged_input_preview` object, required — The input schema with each operator value injected as ``default``.

## Other responses

- `400` — Bad request
- `401` — Authentication required
- `422` — Validation Error

## Changes

- **2026-08-12** `5a5597ebb2d6` — 2 breaking, 9 info
  - the response property `transfer_target/anyOf[subschema #1: TransferTargetView]/destination` became optional for the status `201`
  - response property `transfer_target/anyOf[subschema #1: TransferTargetView]/destination` list-of-types was widened by adding types `null` to media type `application/json` of response `201`
  - added the new optional request property `transfer_target/anyOf[subschema #1: TransferTargetInput]/destination_source`
  - the request property `transfer_target/anyOf[subschema #1: TransferTargetInput]/destination` became optional
  - …7 more

[Change history](https://skmtc.dev/oneloop-hq/apis/feather-api/changes/v1/tools/:tool_id/revisions/post.md)

---

[API](https://skmtc.dev/oneloop-hq/apis/feather-api.md) · [All operations](https://skmtc.dev/oneloop-hq/apis/feather-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/oneloop-hq/feather-api/revisions/9cd7291d4228/schema)
