> ## Documentation Index
> Fetch the complete documentation index at: https://docs.talkpilot.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a tool

> Add a new tool to an agent. The `tool_type` determines which fields
are required in the `config` object.

**Tool types and their config:**

- **`http_request`** — Make HTTP requests to external APIs
  ```json
  { "url": "https://...", "method": "GET", "headers": [{"name":"...", "value":"..."}], "query_params": [{"name":"...", "value":"..."}], "timeout": "5000", "speak_during_execution": true, "speak_after_execution": true }
  ```
  `timeout` is a **string in milliseconds**; header/query entries use the key
  `name`. `"timeout": 30` or `{"key": ...}` are rejected with `400`, because the
  voice agent silently drops such entries.
- **`transfer_call`** — Cold/warm call transfer
  ```json
  { "phone_number": "+49...", "transfer_mode": "cold", "play_hold_music": false }
  ```
- **`monitored_transfer`** — SIP INVITE transfer with monitoring
  ```json
  { "phone_number": "+49...", "timeout_seconds": 20 }
  ```
- **`end_call`** — End the call
  ```json
  { "goodbye_message": "Auf Wiedersehen!" }
  ```
- **`extract_variable`** — Extract structured data from conversation
  ```json
  { "variable_name": "email", "variable_type": "email", "prompt_text": "...", "example_format": "user@example.com", "confirmation_enabled": true }
  ```
- **`play_tone`** — Play DTMF tones
  ```json
  { "tone_type": "dtmf", "dtmf_digit": "1", "duration": 500, "volume": 0.8 }
  ```
- **`knowledge_base`** — Search agent knowledge base
  ```json
  { "top_k": 5, "similarity_threshold": 0.7, "bridging_sentence": "Einen Moment..." }
  ```
- **`set_call_result`** — Let the agent record a call outcome (outbound campaigns); no config, send `{}`
- **`switch_agent`** — Hand the live call over to another agent of your organization
  ```json
  { "target_agent_id": "<agent uuid>", "ring_count": 1, "intro_instructions": "optional" }
  ```
- **`identify_caller`** — Identify the caller against your system via a
  case-number + postcode handshake through your own webhooks
  (`lookup_url`, `fetch_case_url`, optional `verify_plz_url`, digit settings for
  `aktenzeichen` and `plz`). Set this up together with TalkPilot support.
- **`verify_value`** — Deterministic check of a dictated value; every outcome
  referenced in `rules`, `default_outcome` and `unresolved_outcome` must be a key of `outcomes`
  ```json
  { "value": { "name": "plz", "type": "digits" }, "rules": [{ "match": "in", "values": ["10115"], "outcome": "ok" }], "default_outcome": "nein", "unresolved_outcome": "nein", "outcomes": { "ok": { "say": "Passt." }, "nein": { "say": "Leider nicht." } } }
  ```
- **`list_available_slots`** / **`book_appointment`** — appointment booking on the
  organization's connected calendar; both tools share the same config
  ```json
  { "business_hours": { "mon": [["09:00", "12:00"], ["13:00", "17:00"]] }, "duration_minutes": 60, "lead_time_hours": 24, "search_window_days": 14, "contact_mode": "email", "email_variable": "email" }
  ```
- **`resolve_contact`** — clears the contact channel before a booking in `contact_mode: phone`;
  all sentences are yours, `{mitarbeiter}` is the only placeholder
  ```json
  { "employee_name": "Herr Seiler", "confirm_calling_number": "...", "ask_mobile": "...", "ask_mobile_anonymous": "...", "ask_other_number": "...", "ask_email": "...", "no_contact": "..." }
  ```

Each type's required fields and ranges are checked on create and update
(`400 VALIDATION_ERROR` with `details[].field = "config"`).




## OpenAPI

````yaml post /v1/agents/{agentId}/tools
openapi: 3.1.0
info:
  title: TalkPilot API
  version: 1.0.0
  description: >
    The TalkPilot API allows you to programmatically manage your call center
    agents,

    employees, forwarding slots, knowledge base, and more.


    ## Authentication


    All API requests require an API key passed via the `X-API-Key` header:


    ```

    X-API-Key: tp_live_abc123def456...

    ```


    An API key can reach every organization its creator is a member of (see

    `GET /v1/organization`) and can be restricted to specific agents and
    permissions.

    Create and manage keys in the TalkPilot Dashboard under **Settings > API**

    (Dev-Admin only).


    ## Rate Limiting


    Default limits per API key: **60 requests/minute** and **1,000
    requests/hour**

    (both enforced, both configurable per key).


    Rate limit headers are included in every response to a request authenticated

    with an API key (Dashboard JWT requests are not rate limited):

    - `X-RateLimit-Limit` — Max requests per minute

    - `X-RateLimit-Remaining` — Remaining requests in the current minute window

    - `X-RateLimit-Reset` — Unix timestamp roughly 60 seconds in the future


    When rate limited, the API returns `429 Too Many Requests` with
    `Retry-After: 60`

    (minute window) or `Retry-After: 3600` (hour window).


    ## Pagination


    List endpoints support pagination via query parameters:

    - `page` — Page number (default: 1)

    - `limit` — Items per page (default: 20, max: 100)


    Paginated responses include a `pagination` object with `page`, `limit`,
    `total`, and `pages`.


    ## Error Format


    All errors follow a consistent format:


    ```json

    {
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Human-readable description",
        "details": [{ "field": "name", "message": "Required" }],
        "request_id": "req_abc123"
      }
    }

    ```
  contact:
    name: TalkPilot Support
    email: support@talkpilot.io
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
servers:
  - url: https://api.talkpilot.io
    description: Production
security:
  - apiKey: []
tags:
  - name: Health
    description: API health and status
  - name: Agents
    description: Manage AI agent configurations
  - name: Workflow
    description: Multi-state conversation flow of an agent
  - name: Tools
    description: Manage agent tools (HTTP requests, call transfers, etc.)
  - name: Employees
    description: Manage employees linked to agents
  - name: Contacts
    description: >-
      Customer contacts (customer_database) per agent — the voice agent
      recognises callers and greets them by name or tag from here
  - name: Forwarding Slots
    description: Manage call forwarding slot assignments
  - name: Knowledge Base
    description: Manage agent knowledge base documents
  - name: Calls
    description: Read call records and transcripts
  - name: Organization
    description: Organization-level settings
  - name: API Keys
    description: Manage API keys (Dashboard JWT auth only; dev_admin)
paths:
  /v1/agents/{agentId}/tools:
    post:
      tags:
        - Tools
      summary: Create a tool
      description: >
        Add a new tool to an agent. The `tool_type` determines which fields

        are required in the `config` object.


        **Tool types and their config:**


        - **`http_request`** — Make HTTP requests to external APIs
          ```json
          { "url": "https://...", "method": "GET", "headers": [{"name":"...", "value":"..."}], "query_params": [{"name":"...", "value":"..."}], "timeout": "5000", "speak_during_execution": true, "speak_after_execution": true }
          ```
          `timeout` is a **string in milliseconds**; header/query entries use the key
          `name`. `"timeout": 30` or `{"key": ...}` are rejected with `400`, because the
          voice agent silently drops such entries.
        - **`transfer_call`** — Cold/warm call transfer
          ```json
          { "phone_number": "+49...", "transfer_mode": "cold", "play_hold_music": false }
          ```
        - **`monitored_transfer`** — SIP INVITE transfer with monitoring
          ```json
          { "phone_number": "+49...", "timeout_seconds": 20 }
          ```
        - **`end_call`** — End the call
          ```json
          { "goodbye_message": "Auf Wiedersehen!" }
          ```
        - **`extract_variable`** — Extract structured data from conversation
          ```json
          { "variable_name": "email", "variable_type": "email", "prompt_text": "...", "example_format": "user@example.com", "confirmation_enabled": true }
          ```
        - **`play_tone`** — Play DTMF tones
          ```json
          { "tone_type": "dtmf", "dtmf_digit": "1", "duration": 500, "volume": 0.8 }
          ```
        - **`knowledge_base`** — Search agent knowledge base
          ```json
          { "top_k": 5, "similarity_threshold": 0.7, "bridging_sentence": "Einen Moment..." }
          ```
        - **`set_call_result`** — Let the agent record a call outcome (outbound
        campaigns); no config, send `{}`

        - **`switch_agent`** — Hand the live call over to another agent of your
        organization
          ```json
          { "target_agent_id": "<agent uuid>", "ring_count": 1, "intro_instructions": "optional" }
          ```
        - **`identify_caller`** — Identify the caller against your system via a
          case-number + postcode handshake through your own webhooks
          (`lookup_url`, `fetch_case_url`, optional `verify_plz_url`, digit settings for
          `aktenzeichen` and `plz`). Set this up together with TalkPilot support.
        - **`verify_value`** — Deterministic check of a dictated value; every
        outcome
          referenced in `rules`, `default_outcome` and `unresolved_outcome` must be a key of `outcomes`
          ```json
          { "value": { "name": "plz", "type": "digits" }, "rules": [{ "match": "in", "values": ["10115"], "outcome": "ok" }], "default_outcome": "nein", "unresolved_outcome": "nein", "outcomes": { "ok": { "say": "Passt." }, "nein": { "say": "Leider nicht." } } }
          ```
        - **`list_available_slots`** / **`book_appointment`** — appointment
        booking on the
          organization's connected calendar; both tools share the same config
          ```json
          { "business_hours": { "mon": [["09:00", "12:00"], ["13:00", "17:00"]] }, "duration_minutes": 60, "lead_time_hours": 24, "search_window_days": 14, "contact_mode": "email", "email_variable": "email" }
          ```
        - **`resolve_contact`** — clears the contact channel before a booking in
        `contact_mode: phone`;
          all sentences are yours, `{mitarbeiter}` is the only placeholder
          ```json
          { "employee_name": "Herr Seiler", "confirm_calling_number": "...", "ask_mobile": "...", "ask_mobile_anonymous": "...", "ask_other_number": "...", "ask_email": "...", "no_contact": "..." }
          ```

        Each type's required fields and ranges are checked on create and update

        (`400 VALIDATION_ERROR` with `details[].field = "config"`).
      operationId: createTool
      parameters:
        - $ref: '#/components/parameters/AgentId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentToolCreate'
            examples:
              httpRequest:
                summary: HTTP Request tool
                value:
                  name: lookup_customer
                  display_name: Kunden-Lookup
                  description: Looks up customer information by phone number
                  tool_type: http_request
                  config:
                    url: https://crm.example.com/api/customers
                    method: GET
                    headers:
                      - name: Authorization
                        value: Bearer {{API_KEY}}
                    timeout: '5000'
                    speak_during_execution: true
                    speak_after_execution: true
                  priority: 1
                  is_enabled: true
              transferCall:
                summary: Transfer Call tool
                value:
                  name: transfer_to_support
                  description: Transfers the call to human support
                  tool_type: transfer_call
                  config:
                    phone_number: '+4930999888'
                    transfer_mode: cold
                    play_hold_music: false
              endCall:
                summary: End Call tool
                value:
                  name: end_conversation
                  description: Ends the call politely
                  tool_type: end_call
                  config:
                    goodbye_message: Vielen Dank fuer Ihren Anruf. Auf Wiederhoeren!
      responses:
        '201':
          description: Tool created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentTool'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Tool with this name already exists for this agent
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    AgentId:
      name: agentId
      in: path
      required: true
      description: Agent UUID
      schema:
        type: string
        format: uuid
  schemas:
    AgentToolCreate:
      type: object
      required:
        - name
        - description
        - tool_type
        - config
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Internal tool name (lowercase, underscores)
        display_name:
          type:
            - string
            - 'null'
          maxLength: 255
        description:
          type: string
          minLength: 1
          maxLength: 2000
        tool_type:
          $ref: '#/components/schemas/ToolType'
        config:
          type: object
        is_enabled:
          type: boolean
          default: true
        priority:
          type:
            - integer
            - 'null'
        employee_id:
          type:
            - string
            - 'null'
          format: uuid
          description: >
            Link this transfer tool to an employee. `config.phone_number` is
            then derived from the employee and must not be sent with a different
            value — doing so returns `409 CONFLICT`. The employee must belong to
            the same agent and must have a phone number, otherwise `400
            VALIDATION_ERROR`.
    AgentTool:
      type: object
      properties:
        id:
          type: string
          format: uuid
        agent_id:
          type: string
          format: uuid
        name:
          type: string
          description: Internal tool name (used in LLM function calling)
        display_name:
          type:
            - string
            - 'null'
          description: Human-readable display name
        description:
          type: string
          description: Tool description (shown to the LLM to decide when to use it)
        tool_type:
          $ref: '#/components/schemas/ToolType'
        config:
          type: object
          description: Tool-specific configuration (schema depends on tool_type)
        is_enabled:
          type:
            - boolean
            - 'null'
        priority:
          type:
            - integer
            - 'null'
          description: Execution priority (lower number = higher priority)
        employee_id:
          type:
            - string
            - 'null'
          format: uuid
          description: >
            Optional link to an employee, for transfer tools only
            (`transfer_call`, `monitored_transfer`). When set,
            `config.phone_number` is derived from `employees.phone_number` and
            kept in sync automatically — changing the employee's number changes
            the transfer target. `null` means the number is managed on the tool
            itself.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - request_id
          properties:
            code:
              type: string
              enum:
                - VALIDATION_ERROR
                - UNAUTHORIZED
                - FORBIDDEN
                - AGENT_NOT_ACCESSIBLE
                - NOT_FOUND
                - CONFLICT
                - RATE_LIMITED
                - INTERNAL_ERROR
            message:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string
            request_id:
              type: string
    ToolType:
      type: string
      enum:
        - http_request
        - transfer_call
        - monitored_transfer
        - end_call
        - extract_variable
        - play_tone
        - knowledge_base
        - set_call_result
        - identify_caller
        - switch_agent
        - verify_value
        - resolve_contact
        - list_available_slots
        - book_appointment
      description: >
        Tool types accepted by the API:

        - `http_request` — Make HTTP requests to external APIs

        - `transfer_call` — Blind or warm call transfer

        - `monitored_transfer` — SIP INVITE transfer with monitoring

        - `end_call` — End the call with optional goodbye message

        - `extract_variable` — Extract structured data (email, phone, etc.)

        - `play_tone` — Play DTMF tones

        - `knowledge_base` — Search the agent's knowledge base

        - `set_call_result` — Record a call outcome (no config)

        - `identify_caller` — Caller identification handshake via your webhooks

        - `switch_agent` — Hand the call over to another agent

        - `verify_value` — Deterministic check of a dictated value against rules

        - `resolve_contact` — Establish how to reach the caller before booking
        (phone mode)

        - `list_available_slots` — Offer free appointment slots from the
        connected calendar

        - `book_appointment` — Book the chosen slot (same config as
        `list_available_slots`)
  responses:
    ValidationError:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: VALIDATION_ERROR
              message: Invalid request body
              details:
                - field: llm_temperature
                  message: Must be between 0 and 2
              request_id: req_abc123
    Unauthorized:
      description: Missing or invalid authentication
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHORIZED
              message: Invalid or missing API key
              request_id: req_abc123
    Forbidden:
      description: >
        Insufficient permissions (`FORBIDDEN`), or the agent is outside the
        key's

        `allowed_agent_ids` (`AGENT_NOT_ACCESSIBLE`)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missingPermission:
              value:
                error:
                  code: FORBIDDEN
                  message: 'API key lacks required permission: agents:write'
                  request_id: req_abc123
            agentNotAccessible:
              value:
                error:
                  code: AGENT_NOT_ACCESSIBLE
                  message: API key does not have access to this agent
                  request_id: req_abc123
    RateLimited:
      description: Too many requests for this API key (60/minute or 1,000/hour by default)
      headers:
        Retry-After:
          description: >-
            Seconds to wait before retrying — 60 for the minute window, 3600 for
            the hour window
          schema:
            type: integer
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
        X-RateLimit-Reset:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: RATE_LIMITED
              message: Rate limit exceeded. Try again in 60 seconds.
              request_id: req_abc123
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key for external access. Format: `tp_live_<32-hex-chars>`.
        Create keys in the TalkPilot Dashboard under Settings > API.

````