---
title: "Funktionswerkzeuge"
description: "Geben Sie Ihren KI-Agenten Funktionswerkzeuge, die während des Gesprächs externe APIs aufrufen — Kundendaten abrufen, Termine buchen, Datensätze aktualisieren — mit typisierten Parametern."
---

Funktions-Tools ermöglichen Ihren KI-Agenten, während Telefonaten externe APIs aufzurufen. Verwenden Sie sie, um Kundendaten abzurufen, Verfügbarkeiten zu prüfen, Termine zu buchen oder jede von Ihrem Backend unterstützte Aktion auszuführen.

## Funktionsweise

1. Definieren Sie Tools mit einem Schema (welche Argumente das Tool akzeptiert)
2. Geben Sie eine `endpoint`-Konfiguration an (wo ThunderPhone Ihre API aufruft) — oder lassen Sie sie weg, um Tool-Aufrufe über den Webhook Ihrer Organisation zu erhalten
3. Während eines Anrufs entscheidet die KI anhand des Gesprächs, wann ein Tool verwendet werden soll
4. ThunderPhone ruft Ihren Endpunkt mit den Tool-Argumenten auf
5. Die API-Antwort wird an die KI zurückgegeben, damit sie das Gespräch fortsetzen kann

| Funktion | Ausführungsort | Einrichtung |
| --- | --- | --- |
| [Integrierte Tools](/de/guides/built-in-tools) | ThunderPhone | Prompt-Anweisungen; einige Tools benötigen zusätzlich eine Agenteneinstellung |
| [App-Verbindungen](/de/guides/connect-apps) | ThunderPhone und der verbundene Anbieter | Verbinden Sie das Konto und fügen Sie genehmigte Aktionen hinzu |
| [API-Verbindungen](/de/guides/api-connections) und Funktions-Tools | Ihre HTTP-API | Definieren Sie den Endpunkt und das Schema oder empfangen Sie Funktionsaufrufe über einen Webhook |
| [MCP-Server](/de/guides/mcp-servers) | Ein Remote-MCP-Server | Fügen Sie den Server hinzu, ermitteln Sie seine Tools und verknüpfen Sie ihn mit dem Agenten |

---

## Tool-Schema

Jedes Tool folgt dieser Struktur:

```json
{
  "type": "function",
  "function": {
    "name": "search_appointments",
    "description": "Find available appointment slots for a given date",
    "parameters": {
      "type": "object",
      "properties": {
        "date": {
          "type": "string",
          "description": "Date in YYYY-MM-DD format"
        },
        "service": {
          "type": "string",
          "description": "Type of service (e.g., 'consultation', 'follow-up')"
        }
      },
      "required": ["date"]
    }
  },
  "endpoint": {
    "url": "https://api.example.com/appointments/search",
    "method": "POST",
    "headers": {
      "X-Api-Key": "your-api-key"
    }
  },
  "timeout": 120
}
```

### Tool-Konfiguration

| Feld | Typ | Erforderlich | Beschreibung |
|-------|------|----------|-------------|
| `timeout` | Zahl | Nein | Maximale Ausführungszeit in Sekunden (Standard: `20`, Maximum: `180`) |

### Funktionsdefinition

| Feld | Typ | Erforderlich | Beschreibung |
|-------|------|----------|-------------|
| `name` | Zeichenfolge | Ja | Eindeutiger Bezeichner für das Tool |
| `description` | Zeichenfolge | Ja | Erklärt der KI, wann dieses Tool verwendet werden soll |
| `parameters` | Objekt | Ja | JSON-Schema für Tool-Argumente |

### Endpunkt-Konfiguration

| Feld | Typ | Erforderlich | Beschreibung |
|-------|------|----------|-------------|
| `url` | Zeichenfolge | Ja | URL Ihres API-Endpunkts |
| `method` | Zeichenfolge | Nein | HTTP-Methode (Standard: `POST`) |
| `headers` | Objekt | Nein | Einzuschließende benutzerdefinierte Header |

<Note>
  Die `endpoint`-Konfiguration wird **nicht** an das KI-Modell gesendet — sie wird nur von ThunderPhone zur Ausführung des Tool-Aufrufs verwendet.
</Note>

---

## Zwei Aufrufpfade

Welche Anfrage Ihr Server erhält, hängt davon ab, ob das Tool einen
`endpoint` hat:

| | Tool **mit** `endpoint` | Tool **ohne** `endpoint` |
|---|---|---|
| Ziel der Anfrage | Direkt an `endpoint.url` | Die [Legacy-Webhook-URL](/api-reference/organizations#legacy-single-url-webhook) Ihrer Organisation |
| Body | Ausgewähltes Anfrageformat (standardmäßig reine Argumente) | `telephony.tool` / `web.tool`-Envelope |
| Header | Ihre `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` |
| Signaturschlüssel | Webhook-Secret der Organisation | Webhook-Secret der Organisation |

Beide Pfade sind **blockierend** — die KI wartet mitten im Satz auf das
Ergebnis. Das Standard-Timeout beträgt **20 s**; legen Sie das oberste
`timeout` des Tools fest, um eine längere Ausführung bis zum
Plattformmaximum von **180 s** zu erlauben. Halten Sie Handler schnell. Eine Mischung ist möglich:
Bei einem Anruf, dessen Organisation eine Webhook-URL hat, werden Tools mit einem `endpoint`
direkt aufgerufen, während die übrigen auf den Webhook zurückfallen.

## Direkte Endpunktaufrufe

Wenn die KI ein Tool mit einem `endpoint` aufruft, sendet ThunderPhone
eine Anfrage an Ihre URL:

### Anfrage-Header

```http
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature-V2: t=1767225600,v1=5f2c...
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

Benutzerdefinierte Header aus Ihren `endpoint.headers` werden immer
unverändert einbezogen, zusätzlich zu diesen Headern im ThunderPhone-Namensraum:

- `X-ThunderPhone-Signature-V2` — HMAC-SHA256 mit Zeitstempel über
  Methode, Pfad, Abfrage und Body, signiert mit Ihrem **Webhook-Geheimnis der Organisation**.
  Überprüfen Sie diesen und lehnen Sie Anfragen ab, die älter als 5 Minuten sind; siehe
  [Webhook-Signaturen überprüfen](/de/guides/verify-webhook-signatures)
- `X-ThunderPhone-Signature` — Legacy-HMAC-SHA256 der exakten
  Request-Body-Bytes, mit demselben Schlüssel, wird weiterhin für bestehende Verifizierer gesendet
- `X-ThunderPhone-Call-ID` — Die aktuelle Anruf-ID

`Content-Type: application/json` wird gesetzt, sofern Ihr `endpoint.headers`
ihn nicht überschreibt — ein benutzerdefinierter `Content-Type` hat Vorrang.

<Warning>
  Die Signatur verwendet das Webhook-Secret auf Organisationsebene aus
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook)
  als Schlüssel. Wenn Ihre Organisation den Legacy-Webhook nie konfiguriert hat,
  gibt es kein Secret und Tool-Aufrufe enthalten **nur** `X-ThunderPhone-Call-ID` —
  ein Handler, der bei fehlender Signatur einen harten Fehler auslöst, würde sie ablehnen.
  Konfigurieren Sie entweder den Legacy-Webhook, um ein Secret zu erhalten, oder hinterlegen Sie
  Ihr eigenes gemeinsames Secret in `endpoint.headers`.
</Warning>

### Anfrageformat

Jede API-Verbindung verfügt über eine Einstellung für `request_format`. Wählen Sie `vapi` oder
`retell`, wenn ein importiertes Tool weiterhin einen für diese Plattform
erstellten Endpunkt aufrufen soll. Neue und bestehende Verbindungen verwenden standardmäßig `standard`.

Für `POST` / `PUT` / `PATCH` serialisiert ThunderPhone den ausgewählten
Umschlag kanonisch (sortierte Schlüssel, kompakte Trennzeichen). Beide Signaturen
decken diese exakten Bytes ab.

#### Standard

`standard` sendet nur die Tool-Argumente ohne Wrapper. Dies ist die
Standardeinstellung und bewahrt den ursprünglichen Anfrage-Body von ThunderPhone Byte für Byte:

```json
{"date":"2025-01-02","service":"consultation"}
```

#### Vapi

`vapi` sendet Vapis [`tool-calls`-Servernachricht](https://docs.vapi.ai/tools/custom-tools)
in der von Vapi dokumentierten Form. Die `call.id` ist die ThunderPhone-Anruf-ID. Die
Tool-Call-`id` ist für den Aufruf eindeutig und wird wiederverwendet, um das
Ergebnis des Endpunkts zuzuordnen. Der Anruf erscheint sowohl in `toolCallList` als auch
in `toolWithToolCallList`, wobei `function.arguments` ein JSON-Objekt ist:

```json
{
  "message": {
    "type": "tool-calls",
    "timestamp": 1725000000123,
    "call": { "id": "987654321" },
    "toolCallList": [
      {
        "id": "call_00112233445566778899aabbccddeeff",
        "type": "function",
        "function": {
          "name": "search_appointments",
          "arguments": { "date": "2025-01-02", "service": "consultation" }
        }
      }
    ],
    "toolWithToolCallList": [
      {
        "type": "function",
        "function": { "name": "search_appointments" },
        "toolCall": {
          "id": "call_00112233445566778899aabbccddeeff",
          "type": "function",
          "function": {
            "name": "search_appointments",
            "arguments": { "date": "2025-01-02", "service": "consultation" }
          }
        }
      }
    ]
  }
}
```

Nur für Vapi bestimmte Felder wie `assistant`, `artifact` und das vollständige `call`-Objekt
werden nicht gesendet.

Geben Sie Vapis Antwortumschlag mit der passenden Tool-Call-ID zurück:

```json
{
  "results": [
    {
      "toolCallId": "call_00112233445566778899aabbccddeeff",
      "result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
    }
  ]
}
```

ThunderPhone übergibt der KI die entpackte `result`-Zeichenfolge. Aus Kompatibilitätsgründen
akzeptiert es auch einen JSON-Wert für Endpunkte, die bereits einen solchen zurückgeben. Ein
`error` anstelle von `result` wird der KI als Tool-Fehler zurückgegeben. Gibt der
Endpunkt einen fehlerhaften oder nicht passenden Vapi-Umschlag zurück, protokolliert ThunderPhone
eine Warnung und greift auf die standardmäßige Antwortverarbeitung zurück, anstatt den
Anruf fehlschlagen zu lassen.

#### Retell

`retell` sendet die für eine [benutzerdefinierte Retell-Funktion](https://docs.retellai.com/build/single-multi-prompt/custom-function)
dokumentierte Anfrage:

```json
{
  "name": "search_appointments",
  "call": { "call_id": "987654321" },
  "args": { "date": "2025-01-02", "service": "consultation" }
}
```

Das `call`-Objekt enthält nur `call_id`. ThunderPhone enthält keine
Retell-spezifischen Felder, die es beim Versand nicht korrekt bereitstellen kann, wie
`agent_id`, `transcript`, `transcript_object`, `metadata` oder dynamische
Variablen. Retell akzeptiert jeden Antworttext; ThunderPhone leitet ihn
mit der standardmäßigen Antwortverarbeitung weiter.

Für `GET` / `DELETE` werden die Argumente als **Abfrageparameter**
gesendet und der Anfragekörper ist unabhängig von `request_format` leer. Die V2-Signatur
deckt die gesendete Abfragezeichenfolge ab; die Legacy-Signatur wird über
die leere Bytezeichenfolge berechnet. Siehe
[Webhook-Signaturen verifizieren](/de/guides/verify-webhook-signatures).

### Antwort

Geben Sie eine JSON-Antwort mit dem Tool-Ergebnis zurück:

```json
{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}
```

Die Antwort wird formatiert und der KI bereitgestellt, damit sie das
Gespräch fortsetzen kann. Nicht-JSON-Antworten werden als `{"data": "<text>"}`
verpackt; Timeouts und Verbindungsfehler werden der KI als Fehler gemeldet,
sodass der Agent sich entschuldigen und fortfahren kann, statt hängen zu bleiben.

## Versand im Webhook-Modus

Tools **ohne** einen `endpoint` werden als signierte Anfrage vom Typ
`telephony.tool` (Telefonanrufe) oder `web.tool` (Webanrufe) an die
Legacy-Webhook-URL Ihrer Organisation gesendet. Anders als die
[Audit-Benachrichtigungen](/de/webhooks/events), die nach der Ausführung an
Webhook-Endpunkte zugestellt werden, **ist** diese Anfrage die Ausführung —
Ihre HTTP-Antwort ist das Tool-Ergebnis.

```json
{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}
```

`web.tool` enthält `origin_domain` anstelle von `from_number` /
`to_number`. Antworten Sie mit dem Tool-Ergebnis als JSON — gemäß demselben Antwortvertrag wie bei direkten Endpunktaufrufen. Die Anfrage wird wie jeder andere Webhook mit dem Webhook-Secret der Organisation und beiden Signatur-Headern signiert.

<Note>
  Abonnierte [Webhook-Endpunkte](/de/webhooks/endpoints) erhalten zusätzlich
  nach jeder Tool-Ausführung (unabhängig davon, über welchen Pfad sie ausgeführt wurde)
  eine nicht blockierende `telephony.tool` / `web.tool`-**Benachrichtigung
  danach**, einschließlich der Tool-Antwort — nützlich für Audit-Protokolle. Siehe den
  [Ereigniskatalog](/de/webhooks/events).
</Note>

---

## Signaturverifizierung

Direkte Tool-Aufrufe werden wie Webhooks signiert, wobei Ihr Webhook-Secret der Organisation verwendet wird:

- `X-ThunderPhone-Signature-V2` signiert den Zeitstempel, die Methode, den Pfad und die Abfragezeichenfolge wie gesendet sowie die exakten Body-Bytes. Lehnen Sie Anfragen ab, deren Zeitstempel mehr als 5 Minuten von Ihrer Uhrzeit abweicht.
- `X-ThunderPhone-Signature` (Legacy) signiert nur die Body-Bytes, bei `GET` / `DELETE` die leere Bytezeichenfolge. Dieser Header wird weiterhin unverändert gesendet.

Die SDK-Hilfsfunktionen prüfen den V2-Header einschließlich des 5-Minuten-Zeitfensters:

<CodeGroup>
```python Python
import json

from fastapi import FastAPI, HTTPException, Request
from thunderphone import verify_signature

app = FastAPI()

@app.post("/appointments/search")
async def search_appointments(request: Request):
    body = await request.body()
    query = request.scope.get("query_string", b"").decode("latin-1")
    path = request.url.path + (f"?{query}" if query else "")

    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=path,
        body=body,
    ):
        raise HTTPException(status_code=401)

    data = json.loads(body)
    date = data["date"]

    # Look up availability
    slots = await get_available_slots(date)

    return {"available_slots": slots}
```

```javascript Node.js
import express from "express";
import { verifySignature } from "@thunderphone/sdk";

app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
  const ok = verifySignature({
    header: req.header('X-ThunderPhone-Signature-V2'),
    secret: WEBHOOK_SECRET,
    method: req.method,
    path: req.originalUrl,
    body: req.body,
  });
  if (!ok) return res.status(401).send('Invalid signature');

  const { date, service } = JSON.parse(req.body);

  // Look up availability
  const slots = getAvailableSlots(date, service);

  res.json({ available_slots: slots });
});
```
</CodeGroup>

Vollständige Anleitungen — die signierte Zeichenfolge, ein durchgerechnetes Beispiel, Code ohne SDK, der Fall `GET` / `DELETE` und der Hinweis bei fehlendem Secret — finden Sie unter [Webhook-Signaturen verifizieren](/de/guides/verify-webhook-signatures).

---

## Beispiel: Vollständiger Buchungsablauf

Hier ist eine Reihe von Tools für ein vollständiges System zur Terminbuchung:

```json
{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_appointments",
        "description": "Find available appointment slots",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "service": { "type": "string" }
          },
          "required": ["date"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/search",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "book_appointment",
        "description": "Book an appointment at a specific time",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "time": { "type": "string", "description": "HH:MM format" },
            "customer_name": { "type": "string" },
            "customer_phone": { "type": "string" }
          },
          "required": ["date", "time", "customer_name"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/book",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "cancel_appointment",
        "description": "Cancel an existing appointment",
        "parameters": {
          "type": "object",
          "properties": {
            "confirmation_number": { "type": "string" }
          },
          "required": ["confirmation_number"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/cancel",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    }
  ]
}
```

---

## Best Practices

<AccordionGroup>
  <Accordion title="Klare Beschreibungen schreiben">
    Das Feld `description` hilft der KI zu verstehen, **wann** das Tool verwendet werden soll. Beschreiben Sie präzise, was es tut und wann sein Einsatz angemessen ist.
  </Accordion>

  <Accordion title="Fehler angemessen behandeln">
    Geben Sie Fehlermeldungen zurück, die die KI verstehen kann: `{"error": "No slots available for that date"}` statt allgemeiner 500-Fehler.
  </Accordion>

  <Accordion title="Antworten knapp halten">
    Geben Sie nur zurück, was die KI benötigt, um das Gespräch fortzusetzen. Große Nutzdaten verlangsamen die Antwortzeiten.
  </Accordion>

  <Accordion title="Pflichtfelder sinnvoll verwenden">
    Markieren Sie Felder nur dann als `required`, wenn dies wirklich erforderlich ist. Die KI fragt den Benutzer nach erforderlichen Informationen, bevor sie das Tool aufruft.
  </Accordion>
</AccordionGroup>

---

## Verwandte Inhalte

<CardGroup cols={2}>
  <Card title="Integrierte Tools" icon="wrench" href="/de/guides/built-in-tools">
    Lösen Sie von der Plattform verwaltete Anrufaktionen aus, ohne einen Endpunkt zu definieren.
  </Card>
  <Card title="App-Verbindungen" icon="plug" href="/de/guides/connect-apps">
    Von der Plattform verwaltete Tools für HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets und Cal.com — kein Endpunkt erforderlich.
  </Card>
  <Card title="MCP-Server" icon="server" href="/de/guides/mcp-servers">
    Binden Sie einen MCP-Server an und lassen Sie den Agenten dessen Tools aufrufen.
  </Card>
  <Card title="API-Verbindungen" icon="code" href="/de/guides/api-connections">
    Wiederverwendbare REST-Integrationen, die Sie an Agenten anbinden können.
  </Card>
  <Card title="Webhook-Signaturen überprüfen" icon="shield-check" href="/de/guides/verify-webhook-signatures">
    Eine Prüfhilfe für Webhooks und Tool-Aufrufe.
  </Card>
</CardGroup>
