> ## 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.

# Narzędzia funkcji

> Pozwól swoim agentom AI wywoływać zewnętrzne interfejsy API podczas rozmów

Narzędzia funkcji umożliwiają agentom AI wywoływanie zewnętrznych interfejsów API podczas rozmów telefonicznych. Używaj ich do wyszukiwania danych klientów, sprawdzania dostępności, umawiania wizyt lub wykonywania dowolnych działań obsługiwanych przez Twój backend.

## Jak to działa

1. Definiujesz narzędzia za pomocą schematu (jakie argumenty akceptuje narzędzie)
2. Podajesz konfigurację `endpoint` (gdzie ThunderPhone wywołuje Twoje API) — lub pomijasz ją, aby otrzymywać wywołania narzędzi na webhooku organizacji
3. Podczas rozmowy AI decyduje, kiedy użyć narzędzia, na podstawie rozmowy
4. ThunderPhone wywołuje Twój endpoint z argumentami narzędzia
5. Odpowiedź Twojego API jest przekazywana z powrotem do AI, aby kontynuować rozmowę

<Note>
  Narzędzia funkcji to ścieżka, w której używasz własnego API. ThunderPhone oferuje również
  narzędzia zarządzane przez platformę, które nie wymagają endpointu:
  [połączenia aplikacji](/pl/guides/connect-apps) (HubSpot, Salesforce, Slack,
  Kalendarz Google, Arkusze Google, Cal.com),
  [połączenia API](/pl/guides/api-connections) oraz
  [serwery MCP](/pl/guides/mcp-servers).
</Note>

***

## Schemat narzędzia

Każde narzędzie ma następującą 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"
    }
  }
}
```

### Definicja funkcji

| Pole          | Typ    | Wymagane | Opis                                   |
| ------------- | ------ | -------- | -------------------------------------- |
| `name`        | string | Tak      | Unikalny identyfikator narzędzia       |
| `description` | string | Tak      | Wyjaśnia AI, kiedy użyć tego narzędzia |
| `parameters`  | object | Tak      | Schemat JSON argumentów narzędzia      |

### Konfiguracja endpointu

| Pole      | Typ    | Wymagane | Opis                                     |
| --------- | ------ | -------- | ---------------------------------------- |
| `url`     | string | Tak      | Adres URL endpointu Twojego API          |
| `method`  | string | Nie      | Metoda HTTP (domyślnie: `POST`)          |
| `headers` | object | Nie      | Niestandardowe nagłówki do uwzględnienia |

<Note>
  Konfiguracja `endpoint` **nie** jest wysyłana do modelu AI — jest używana wyłącznie przez ThunderPhone do wykonania wywołania narzędzia.
</Note>

***

## Dwie ścieżki wywołania

To, które żądanie otrzyma Twój serwer, zależy od tego, czy narzędzie ma
`endpoint`:

|                      | Narzędzie **z** `endpoint`                                                       | Narzędzie **bez** `endpoint`                                                                     |
| -------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Dokąd trafia żądanie | Bezpośrednio do `endpoint.url`                                                   | Starszy [adres URL webhooka organizacji](/api-reference/organizations#legacy-single-url-webhook) |
| Treść                | **Same argumenty narzędzia**                                                     | Koperta `telephony.tool` / `web.tool`                                                            |
| Nagłówki             | Twoje `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature`                                                      |
| Klucz podpisywania   | Sekret webhooka organizacji                                                      | Sekret webhooka organizacji                                                                      |

Obie ścieżki są **blokujące** — AI czeka w środku zdania na
wynik — z limitem czasu **20 s**. Zadbaj o szybkie handlery. Możesz je
łączyć: w rozmowie, której organizacja ma adres URL webhooka, narzędzia z `endpoint` są
wywoływane bezpośrednio, a pozostałe korzystają z webhooka.

## Bezpośrednie wywołania endpointów

Gdy AI wywołuje narzędzie z `endpoint`, ThunderPhone wysyła
żądanie do Twojego adresu URL:

### Nagłówki żądania

```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
```

Niestandardowe nagłówki z `endpoint.headers` są zawsze dołączane
dosłownie, wraz z dwoma nagłówkami w przestrzeni nazw ThunderPhone:

* `X-ThunderPhone-Signature` — HMAC-SHA256 dokładnych bajtów treści
  żądania, z kluczem będącym Twoim **sekretem webhooka organizacji**
* `X-ThunderPhone-Call-ID` — identyfikator bieżącego połączenia

`Content-Type: application/json` jest ustawiane, chyba że zostanie
zastąpione przez `endpoint.headers` — niestandardowy `Content-Type` ma pierwszeństwo.

<Warning>
  Podpis jest tworzony z użyciem sekretu webhooka na poziomie organizacji z
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Jeśli Twoja organizacja nigdy nie skonfigurowała starszego webhooka, nie ma
  sekretu, a wywołania narzędzi zawierają **wyłącznie** `X-ThunderPhone-Call-ID` —
  obsługa, która kończy działanie błędem przy braku podpisu, odrzuciłaby je.
  Skonfiguruj starszy webhook, aby uzyskać sekret, lub umieść własny
  współdzielony sekret w `endpoint.headers`.
</Warning>

### Treść żądania

W przypadku `POST` / `PUT` / `PATCH` treść zawiera **wyłącznie** argumenty
narzędzia (bez opakowania), serializowane kanonicznie (posortowane klucze,
zwarte separatory):

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

W przypadku `GET` / `DELETE` argumenty są wysyłane jako **parametry zapytania**,
a treść jest pusta — podpis jest wtedy obliczany na pustym
ciągu bajtów. Zobacz
[Weryfikowanie podpisów webhooków](/pl/guides/verify-webhook-signatures).

### Odpowiedź

Zwróć odpowiedź JSON z wynikiem narzędzia:

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

Odpowiedź jest formatowana i przekazywana AI, aby kontynuowało
rozmowę. Odpowiedzi inne niż JSON są opakowywane jako `{"data": "<text>"}`;
przekroczenia limitu czasu i błędy połączenia są zgłaszane AI jako błędy, dzięki czemu
agent może przeprosić i przejść dalej zamiast się zatrzymać.

## Dystrybucja w trybie webhooka

Narzędzia **bez** `endpoint` są wysyłane na starszy adres URL webhooka Twojej
organizacji jako podpisane żądanie `telephony.tool` (połączenia telefoniczne) lub `web.tool`
(połączenia internetowe). W przeciwieństwie do [powiadomień audytowych](/pl/webhooks/events)
dostarczanych do endpointów webhooków po wykonaniu, to żądanie **jest**
wykonaniem — Twoja odpowiedź HTTP jest wynikiem narzędzia.

```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` zawiera `origin_domain` zamiast `from_number` /
`to_number`. Odpowiedz wynikiem narzędzia w formacie JSON — obowiązuje ten sam kontrakt
odpowiedzi co w przypadku bezpośrednich wywołań endpointów. Żądanie jest podpisywane sekretem
webhooka organizacji na podstawie nieprzetworzonej treści, tak jak każdy inny webhook.

<Note>
  Subskrybowane [endpointy webhooków](/pl/webhooks/endpoints) dodatkowo
  otrzymują nieblokujące **powiadomienie** `telephony.tool` / `web.tool`
  **po** wykonaniu każdego narzędzia (niezależnie od ścieżki, która je uruchomiła),
  wraz z odpowiedzią narzędzia — przydatne do ścieżek audytu. Zobacz
  [katalog zdarzeń](/pl/webhooks/events).
</Note>

***

## Weryfikacja podpisu

Bezpośrednie wywołania narzędzi są podpisywane tak samo jak webhooki:

* HMAC-SHA256 obliczany na dokładnych bajtach treści żądania (kanoniczny JSON — posortowane klucze, bez dodatkowych białych znaków)
* Z użyciem sekretu webhooka organizacji
* Narzędzia `GET` / `DELETE` podpisują pusty ciąg bajtów

<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>

Pełne przykłady — w tym przypadek pustej treści i zastrzeżenie dotyczące braku sekretu — znajdziesz w [Weryfikowanie podpisów webhooków](/pl/guides/verify-webhook-signatures).

***

## Przykład: kompletny proces rezerwacji

Oto zestaw narzędzi dla kompletnego systemu umawiania wizyt:

```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" }
      }
    }
  ]
}
```

***

## Najlepsze praktyki

<AccordionGroup>
  <Accordion title="Pisz jasne opisy">
    Pole `description` pomaga AI zrozumieć, **kiedy** użyć narzędzia. Precyzyjnie opisz, co robi i kiedy należy go użyć.
  </Accordion>

  <Accordion title="Obsługuj błędy w odpowiedni sposób">
    Zwracaj komunikaty o błędach, które AI może zrozumieć: `{"error": "No slots available for that date"}` zamiast ogólnych błędów 500.
  </Accordion>

  <Accordion title="Zachowaj zwięzłość odpowiedzi">
    Zwracaj tylko to, czego AI potrzebuje, aby kontynuować rozmowę. Duże ładunki danych spowalniają czas odpowiedzi.
  </Accordion>

  <Accordion title="Rozważnie używaj wymaganych pól">
    Oznaczaj pola jako `required` tylko wtedy, gdy jest to naprawdę konieczne. AI poprosi użytkownika o wymagane informacje przed wywołaniem narzędzia.
  </Accordion>
</AccordionGroup>

***

## Powiązane

<CardGroup cols={2}>
  <Card title="Połączenia aplikacji" icon="plug" href="/pl/guides/connect-apps">
    Narzędzia zarządzane przez platformę dla HubSpot, Salesforce, Slack, Kalendarza Google, Arkuszy Google i Cal.com — nie wymagają punktu końcowego.
  </Card>

  <Card title="Serwery MCP" icon="server" href="/pl/guides/mcp-servers">
    Podłącz serwer MCP i pozwól agentowi wywoływać jego narzędzia.
  </Card>

  <Card title="Połączenia API" icon="code" href="/pl/guides/api-connections">
    Integracje REST wielokrotnego użytku, które możesz podłączać do agentów.
  </Card>

  <Card title="Weryfikowanie podpisów webhooków" icon="shield-check" href="/pl/guides/verify-webhook-signatures">
    Jedno narzędzie pomocnicze do weryfikacji webhooków i wywołań narzędzi.
  </Card>
</CardGroup>
