---
title: "Create Tool"
method: POST
path: "/v2/tools"
tags: ["Tools"]
---

# Create Tool

`POST /v2/tools`

Create a standalone tool that can be attached to one or more PALs via [Attach Tools To PAL](/api-reference/pal-tools/attach-tools-to-pal).

**In-call tools** (`trigger_type: in_call`, default) are invoked during the conversation by an LLM (`origin: llm`) or a perception model (`origin: vision` / `origin: audio`).

**Post-call actions** (`trigger_type: post_call`) run once after the conversation ends; omit `origin` and set `delivery.api` (HTTPS webhook). See [Post-Call Actions](/sections/conversational-video-interface/pal/post-call-tool).

Every tool dispatches via **exactly one** delivery channel:

- `delivery.app_message: true` (default) - calls land on your frontend as a `conversation.tool_call` event over the Daily data channel.
- `delivery.api` - Tavus makes an HTTPS request to a URL you configure. Supports five auth types and `{placeholder}` templating in the URL path, query string, and body.

See [Tools Overview](/sections/conversational-video-interface/pal/tools), [LLM Tool Delivery](/sections/conversational-video-interface/pal/llm-tool-delivery), and [LLM Tool Auth](/sections/conversational-video-interface/pal/llm-tool-auth) for the conceptual model.

## Request body

- object
  - `name` string, required — Function name the LLM uses to call the tool. Must match OpenAI function-naming rules (letters, digits, underscores; must start with a letter or underscore; max 64 characters) and be unique within your account.
  - `description` string, required — Natural-language description used by the LLM to decide when to call the tool. `description` plus the serialized `parameters` together must be at most 10000 characters.
  - `parameters` object — JSON Schema describing the tool's arguments. Follows the standard OpenAI function-calling shape. Property names starting with `tavus_` are reserved for Tavus-injected placeholders and are rejected.
  - `delivery` ToolDelivery — How the tool call is dispatched. Exactly one channel must be enabled: - `app_message: true` alone - the call is delivered to your frontend over the Daily data channel as a `conversation.tool_call` event. - `api` set with `app_message: false` - Tavus makes an HTTPS request to `api.url`. If `delivery` is omitted on create, the default is `{ "app_message": true }`.
    - `app_message` boolean — Set to `true` to deliver tool calls to your frontend as `conversation.tool_call` events. Mutually exclusive with `api`.
    - `api` ToolApiDelivery — HTTPS request configuration for tool calls delivered via API.
      - `url` string, required — HTTPS URL Tavus calls. Must use `https://`. Hostname must not point at private / loopback / link-local / metadata-server IP space and must not contain `{placeholder}` substitutions - placeholders are only resolved in the path, query string, and body.
      - `method` 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' — HTTP method. `GET`, `HEAD`, and `DELETE` reject `body_template`.
      - `timeout` number — Request timeout in seconds. Must be greater than 0 and at most 60. Default 10.
      - `headers` object — Static HTTP headers sent with every request. Keys and values must be strings.
      - `auth` ToolAuth — Outbound authentication for API delivery. The required fields depend on `type`: - `none` - no auth. - `bearer` - `token` is sent as `Authorization: Bearer <token>`. - `basic` - `username` + `password` are encoded into `Authorization: Basic ...`. - `api_key` - `name` + `value` are sent as a header (`location: header`, default) or query parameter (`location: query`). - `hmac` - `secret` signs a fixed Tavus envelope body with HMAC-SHA256; the signature is sent in the `X-Tavus-Signature` header. HMAC mode ignores `body_template`, `query_params`, and URL placeholders. - `oauth2_client_credentials` - Tavus does a client-credentials exchange against `token_url` using `client_id` + `client_secret` (and optional `scope`) and uses the returned bearer token to call the tool URL. On response, all secret fields (`token`, `password`, `value`, `secret`, `client_secret`) are scrubbed to `********`. Echoing that back on PATCH is rejected; omit the field instead to keep the stored secret.
        - `type` 'none' | 'bearer' | 'basic' | 'api_key' | 'hmac' | 'oauth2_client_credentials', required — Auth strategy.
        - `token` string — Bearer token. Required when `type=bearer`.
        - `username` string — HTTP Basic username. Required when `type=basic`.
        - `password` string — HTTP Basic password. Required when `type=basic`.
        - `name` string — API key header / query parameter name. Required when `type=api_key`.
        - `value` string — API key value. Required when `type=api_key`.
        - `location` 'header' | 'query' — Where the API key is sent. Used only when `type=api_key`.
        - `secret` string — HMAC shared secret. Required when `type=hmac`.
        - `token_url` string — OAuth2 token endpoint. Must use HTTPS and pass the same SSRF rules as the tool URL. Required when `type=oauth2_client_credentials`.
        - `client_id` string — OAuth2 client ID. Required when `type=oauth2_client_credentials`.
        - `client_secret` string — OAuth2 client secret. Required when `type=oauth2_client_credentials`.
        - `scope` string — Optional OAuth2 scope string. Used only when `type=oauth2_client_credentials`.
      - `body_template` object — Optional JSON object used as the request body. String values support `{placeholder}` substitutions referencing keys declared in the tool's `parameters.properties`. Rejected when `method` is `GET`, `HEAD`, or `DELETE`, and ignored when `auth.type` is `hmac` (which uses a fixed Tavus envelope).
      - `query_params` object — Static query parameters appended to the URL. Keys and values must be strings; values support `{placeholder}` substitutions. Ignored when `auth.type` is `hmac`.
      - `content_type` string — Override the request `Content-Type` header. Defaults to `application/json` when not set.
  - `trigger_type` 'in_call' | 'post_call' — When the tool runs. `in_call` (default) offers the tool during the live conversation. `post_call` runs once after the conversation ends; omit `origin` and set `delivery.api` (HTTPS webhook). See [Post-Call Actions](/sections/conversational-video-interface/pal/post-call-tool).
  - `origin` 'llm' | 'vision' | 'audio', nullable — Live modality for in-call tools only. Required when `trigger_type` is `in_call` (defaults to `llm`). Must be omitted or null for `post_call` tools.
  - `on_call` 'generate_filler' | 'static_filler' | 'silent' | 'passthrough', nullable — What the PAL does **while** the tool call is in flight. `generate_filler` (default for `llm` tools) lets the LLM speak a contextual filler line. `static_filler` plays the `static_filler` string verbatim. `silent` says nothing. `passthrough` skips filler entirely. Must be null for perception tools.
  - `on_resolve` 'generate_response' | 'response_in_result' | 'add_to_context' | 'fire_and_forget', nullable — what the PAL does **after** the tool returns. `generate_response` re-prompts the LLM with the result so it can answer naturally. `response_in_result` speaks the response text returned by your endpoint verbatim. `add_to_context` silently adds the result to conversation context. `fire_and_forget` ignores the result. Perception tools must use `fire_and_forget`.
  - `static_filler` string, nullable — Phrase the PAL speaks while the tool call is in flight. Required when `on_call` is `static_filler`; must be null for perception tools.

## Response `200`

Tool created

- Tool — A standalone tool definition. Returned by every tool endpoint and embedded in the `data` array of the PAL-tool endpoints.
  - `tool_id` string — Unique identifier for the tool. System tools use their `name` as the `tool_id` (e.g. `end_call`).
  - `owner_id` integer, nullable — Internal user ID that owns the tool. `null` for built-in system tools.
  - `name` string — Function name the LLM uses to call the tool.
  - `description` string — Natural-language description of the tool.
  - `parameters` object — JSON Schema describing the tool's arguments.
  - `delivery` ToolDelivery — How the tool call is dispatched. Exactly one channel must be enabled: - `app_message: true` alone - the call is delivered to your frontend over the Daily data channel as a `conversation.tool_call` event. - `api` set with `app_message: false` - Tavus makes an HTTPS request to `api.url`. If `delivery` is omitted on create, the default is `{ "app_message": true }`.
    - `app_message` boolean — Set to `true` to deliver tool calls to your frontend as `conversation.tool_call` events. Mutually exclusive with `api`.
    - `api` ToolApiDelivery — HTTPS request configuration for tool calls delivered via API.
      - `url` string, required — HTTPS URL Tavus calls. Must use `https://`. Hostname must not point at private / loopback / link-local / metadata-server IP space and must not contain `{placeholder}` substitutions - placeholders are only resolved in the path, query string, and body.
      - `method` 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' — HTTP method. `GET`, `HEAD`, and `DELETE` reject `body_template`.
      - `timeout` number — Request timeout in seconds. Must be greater than 0 and at most 60. Default 10.
      - `headers` object — Static HTTP headers sent with every request. Keys and values must be strings.
      - `auth` ToolAuth — Outbound authentication for API delivery. The required fields depend on `type`: - `none` - no auth. - `bearer` - `token` is sent as `Authorization: Bearer <token>`. - `basic` - `username` + `password` are encoded into `Authorization: Basic ...`. - `api_key` - `name` + `value` are sent as a header (`location: header`, default) or query parameter (`location: query`). - `hmac` - `secret` signs a fixed Tavus envelope body with HMAC-SHA256; the signature is sent in the `X-Tavus-Signature` header. HMAC mode ignores `body_template`, `query_params`, and URL placeholders. - `oauth2_client_credentials` - Tavus does a client-credentials exchange against `token_url` using `client_id` + `client_secret` (and optional `scope`) and uses the returned bearer token to call the tool URL. On response, all secret fields (`token`, `password`, `value`, `secret`, `client_secret`) are scrubbed to `********`. Echoing that back on PATCH is rejected; omit the field instead to keep the stored secret.
        - `type` 'none' | 'bearer' | 'basic' | 'api_key' | 'hmac' | 'oauth2_client_credentials', required — Auth strategy.
        - `token` string — Bearer token. Required when `type=bearer`.
        - `username` string — HTTP Basic username. Required when `type=basic`.
        - `password` string — HTTP Basic password. Required when `type=basic`.
        - `name` string — API key header / query parameter name. Required when `type=api_key`.
        - `value` string — API key value. Required when `type=api_key`.
        - `location` 'header' | 'query' — Where the API key is sent. Used only when `type=api_key`.
        - `secret` string — HMAC shared secret. Required when `type=hmac`.
        - `token_url` string — OAuth2 token endpoint. Must use HTTPS and pass the same SSRF rules as the tool URL. Required when `type=oauth2_client_credentials`.
        - `client_id` string — OAuth2 client ID. Required when `type=oauth2_client_credentials`.
        - `client_secret` string — OAuth2 client secret. Required when `type=oauth2_client_credentials`.
        - `scope` string — Optional OAuth2 scope string. Used only when `type=oauth2_client_credentials`.
      - `body_template` object — Optional JSON object used as the request body. String values support `{placeholder}` substitutions referencing keys declared in the tool's `parameters.properties`. Rejected when `method` is `GET`, `HEAD`, or `DELETE`, and ignored when `auth.type` is `hmac` (which uses a fixed Tavus envelope).
      - `query_params` object — Static query parameters appended to the URL. Keys and values must be strings; values support `{placeholder}` substitutions. Ignored when `auth.type` is `hmac`.
      - `content_type` string — Override the request `Content-Type` header. Defaults to `application/json` when not set.
  - `is_system_tool` boolean — Whether this is a built-in system tool. System tools cannot be modified or deleted.
  - `trigger_type` 'in_call' | 'post_call' — When the tool runs. `post_call` tools execute server-side after the conversation ends via `delivery.api` (HTTPS webhook).
  - `origin` 'llm' | 'vision' | 'audio', nullable — Live modality for in-call tools. Null for post-call tools.
  - `on_call` 'generate_filler' | 'static_filler' | 'silent' | 'passthrough', nullable — What the PAL does while the tool call is in flight. Always null for perception tools.
  - `on_resolve` 'generate_response' | 'response_in_result' | 'add_to_context' | 'fire_and_forget', nullable — What the PAL does after the tool returns.
  - `static_filler` string, nullable — Phrase the PAL speaks while the tool call is in flight. Set when `on_call` is `static_filler`.
  - `created_at` string — ISO 8601 timestamp of when the tool was created.
  - `updated_at` string — ISO 8601 timestamp of when the tool was last updated.

## Other responses

- `400` — Bad Request - validation error
- `401` — Unauthorized
- `409` — Conflict - a tool with this name already exists

---

[API](https://skmtc.dev/tavus/apis/tavus-developer-api-collection.md) · [All operations](https://skmtc.dev/tavus/apis/tavus-developer-api-collection/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/tavus/tavus-developer-api-collection/revisions/c878e2f6508d/schema)
