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

# Funktionswerkzeuge

> Lassen Sie Ihre KI-Agenten während Gesprächen externe APIs aufrufen

Funktionstools ermöglichen Ihren Sprachagenten, während Telefonaten externe APIs aufzurufen. Verwenden Sie sie, um Kundendaten abzurufen, Verfügbarkeiten zu prüfen, Termine zu buchen oder jede Aktion auszuführen, die Ihr Backend unterstützt.

## So funktioniert es

1. Sie definieren Tools mit einem Schema (welche Argumente das Tool akzeptiert)
2. Sie geben eine `endpoint`-Konfiguration an (wo ThunderPhone Ihre API aufruft) — oder lassen 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, um das Gespräch fortzusetzen

<Note>
  Funktionstools sind der Weg, Ihre eigene API einzubringen. ThunderPhone
  bietet außerdem plattformverwaltete Tools, die keinen Endpunkt benötigen:
  [App-Verbindungen](/de/guides/connect-apps) (HubSpot, Salesforce, Slack,
  Google Calendar, Google Sheets, Cal.com),
  [API-Verbindungen](/de/guides/api-connections) und
  [MCP-Server](/de/guides/mcp-servers).
</Note>

***

## Tool-Schema

Jedes Tool folgt dieser Struktur:

```json theme={null}
{
  "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"
    }
  }
}
```

### Funktionsdefinition

| Feld          | Typ    | Erforderlich | Beschreibung                                           |
| ------------- | ------ | ------------ | ------------------------------------------------------ |
| `name`        | string | Ja           | Eindeutige Kennung für das Tool                        |
| `description` | string | Ja           | Erklärt der KI, wann dieses Tool verwendet werden soll |
| `parameters`  | object | Ja           | JSON-Schema für Tool-Argumente                         |

### Endpunktkonfiguration

| Feld      | Typ    | Erforderlich | Beschreibung                               |
| --------- | ------ | ------------ | ------------------------------------------ |
| `url`     | string | Ja           | URL Ihres API-Endpunkts                    |
| `method`  | string | Nein         | HTTP-Methode (Standard: `POST`)            |
| `headers` | object | Nein         | Benutzerdefinierte einzuschließende Header |

<Note>
  Die `endpoint`-Konfiguration wird **nicht** an das KI-Modell gesendet — sie wird nur von ThunderPhone verwendet, um den Tool-Aufruf auszuführen.
</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`                                                                            |
| ---------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Wohin die Anfrage geht | Direkt an `endpoint.url`                                                        | Die [Legacy-Webhook-URL](/api-reference/organizations#legacy-single-url-webhook) Ihrer Organisation |
| Body                   | **Reine Tool-Argumente**                                                        | `telephony.tool` / `web.tool`-Umschlag                                                              |
| Header                 | Ihre `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `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 — mit einem Timeout von **20 s**. 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 Endpoint-Aufrufe

Wenn die KI ein Tool aufruft, das einen `endpoint` hat, sendet ThunderPhone
eine Anfrage an Ihre URL:

### Anfrage-Header

```http theme={null}
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

Benutzerdefinierte Header aus Ihrem `endpoint.headers` werden immer
unverändert eingeschlossen, zusätzlich zu zwei Headern im ThunderPhone-Namespace:

* `X-ThunderPhone-Signature` — HMAC-SHA256 der exakten Anfrage-Body-
  Bytes, mit Ihrem **Webhook-Secret der Organisation** als Schlüssel
* `X-ThunderPhone-Call-ID` — Die ID des aktuellen Anrufs

`Content-Type: application/json` wird gesetzt, sofern Ihre `endpoint.headers`
es nicht überschreiben — ein benutzerdefinierter `Content-Type` hat Vorrang.

<Warning>
  Die Signatur wird mit dem Webhook-Secret auf Organisationsebene aus
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook)
  erstellt. Wenn Ihre Organisation den Legacy-Webhook noch nie konfiguriert hat,
  gibt es kein Secret und Tool-Aufrufe enthalten **nur**
  `X-ThunderPhone-Call-ID` — ein Handler, der bei einer fehlenden Signatur
  sofort fehlschlägt, 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>

### Anfrage-Body

Bei `POST` / `PUT` / `PATCH` enthält der Body **nur** die Tool-
Argumente (ohne Wrapper), kanonisch serialisiert (sortierte Schlüssel,
kompakte Trennzeichen):

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

Bei `GET` / `DELETE` werden die Argumente als **Abfrageparameter**
gesendet und der Body ist leer — die Signatur wird dann über die leere
Byte-Zeichenfolge berechnet. Siehe
[Webhook-Signaturen überprüfen](/de/guides/verify-webhook-signatures).

### Antwort

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

```json theme={null}
{
  "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; Zeitüberschreitungen und Verbindungsfehler werden der KI als Fehler
gemeldet, damit der Agent sich entschuldigen und fortfahren kann, statt zu
blockieren.

## Versand im Webhook-Modus

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

```json theme={null}
{
  "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 — derselbe
Antwortvertrag wie bei direkten Endpoint-Aufrufen. Die Anfrage wird wie jeder
andere Webhook mit dem Webhook-Secret der Organisation über den unverarbeiteten
Body signiert.

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

***

## Signaturüberprüfung

Direkte Tool-Aufrufe werden genauso signiert wie Webhooks:

* HMAC-SHA256 über die exakten Bytes des Anfragebodys (das kanonische JSON — sortierte Schlüssel, keine zusätzlichen Leerzeichen)
* Mit Ihrem Organisations-Webhook-Secret als Schlüssel
* `GET`- / `DELETE`-Tools signieren die leere Byte-Zeichenfolge

<CodeGroup>
  ```python Python theme={null}
  import hmac
  import hashlib

  def verify_tool_call(body: bytes, signature: str, secret: str) -> bool:
      expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
      return hmac.compare_digest(expected, signature)

  @app.post("/appointments/search")
  async def search_appointments(request: Request):
      body = await request.body()
      signature = request.headers.get("X-ThunderPhone-Signature", "")

      if not verify_tool_call(body, signature, WEBHOOK_SECRET):
          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 theme={null}
  app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
    const signature = req.headers['x-thunderphone-signature'] || '';
    const expected = crypto
      .createHmac('sha256', WEBHOOK_SECRET)
      .update(req.body)
      .digest('hex');

    if (!signature ||
        signature.length !== expected.length ||
        !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
      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 Beispiele — einschließlich des Falls mit leerem Body und des Hinweises bei fehlendem Secret —
finden Sie unter [Webhook-Signaturen überprüfen](/de/guides/verify-webhook-signatures).

***

## Beispiel: Vollständiger Buchungsablauf

Hier ist eine Reihe von Tools für ein vollständiges Terminbuchungssystem:

```json theme={null}
{
  "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 verfassen">
    Das Feld `description` hilft der KI zu verstehen, **wann** das Tool verwendet werden soll. Beschreiben Sie konkret, was es tut und wann es geeignet ist.
  </Accordion>

  <Accordion title="Fehler zuverlässig 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 kurz halten">
    Geben Sie nur zurück, was die KI benötigt, um das Gespräch fortzusetzen. Große Nutzlasten verlangsamen die Antwortzeiten.
  </Accordion>

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

***

## Verwandte Themen

<CardGroup cols={2}>
  <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 Endpoint 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 verifizieren" icon="shield-check" href="/de/guides/verify-webhook-signatures">
    Ein Verifizierungshelfer für Webhooks und Tool-Aufrufe.
  </Card>
</CardGroup>
