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

# Instrumente de funcții

> Permiteți agenților vocali cu IA să apeleze API-uri externe în timpul conversațiilor

Instrumentele de funcție le permit agenților dvs. AI să invoce API-uri externe în timpul apelurilor telefonice. Folosiți-le pentru a căuta date despre clienți, a verifica disponibilitatea, a programa întâlniri sau a efectua orice acțiune acceptată de backendul dvs.

## Cum funcționează

1. Definiți instrumente cu o schemă (ce argumente acceptă instrumentul)
2. Furnizați o configurație `endpoint` (unde ThunderPhone apelează API-ul dvs.) — sau omiteți-o pentru a primi apeluri de instrumente pe webhookul organizației dvs.
3. În timpul unui apel, AI-ul decide când să utilizeze un instrument pe baza conversației
4. ThunderPhone apelează endpointul dvs. cu argumentele instrumentului
5. Răspunsul API-ului dvs. este transmis înapoi AI-ului pentru a continua conversația

<Note>
  Instrumentele de funcție reprezintă opțiunea în care vă furnizați propriul API. ThunderPhone oferă și
  instrumente gestionate de platformă, care nu necesită endpoint:
  [conexiuni de aplicații](/ro/guides/connect-apps) (HubSpot, Salesforce, Slack,
  Google Calendar, Google Sheets, Cal.com),
  [conexiuni API](/ro/guides/api-connections) și
  [servere MCP](/ro/guides/mcp-servers).
</Note>

***

## Schema instrumentului

Fiecare instrument urmează această structură:

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

### Definiția funcției

| Câmp          | Tip    | Obligatoriu | Descriere                                          |
| ------------- | ------ | ----------- | -------------------------------------------------- |
| `name`        | șir    | Da          | Identificator unic pentru instrument               |
| `description` | șir    | Da          | Explică AI-ului când să utilizeze acest instrument |
| `parameters`  | obiect | Da          | Schemă JSON pentru argumentele instrumentului      |

### Configurarea endpointului

| Câmp      | Tip    | Obligatoriu | Descriere                         |
| --------- | ------ | ----------- | --------------------------------- |
| `url`     | șir    | Da          | URL-ul endpointului API-ului dvs. |
| `method`  | șir    | Nu          | Metodă HTTP (implicit: `POST`)    |
| `headers` | obiect | Nu          | Antete personalizate de inclus    |

<Note>
  Configurația `endpoint` **nu** este trimisă modelului AI — este utilizată doar de ThunderPhone pentru a executa apelul instrumentului.
</Note>

***

## Două căi de invocare

Solicitarea pe care o primește serverul dvs. depinde de existența unui
`endpoint` pentru instrument:

|                               | Instrument **cu** `endpoint`                                                       | Instrument **fără** `endpoint`                                                                           |
| ----------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Unde este trimisă solicitarea | Direct la `endpoint.url`                                                           | [URL-ul webhookului legacy](/api-reference/organizations#legacy-single-url-webhook) al organizației dvs. |
| Corp                          | **Doar argumentele instrumentului**                                                | Plic `telephony.tool` / `web.tool`                                                                       |
| Antete                        | `endpoint.headers` al dvs. + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature`                                                              |
| Cheie de semnare              | Secretul webhookului organizației                                                  | Secretul webhookului organizației                                                                        |

Ambele căi sunt **blocante** — AI-ul așteaptă rezultatul în mijlocul
propoziției — cu o expirare după **20 s**. Mențineți handlerele rapide. O combinație este acceptată:
într-un apel a cărui organizație are un URL de webhook, instrumentele cu un `endpoint` sunt
apelate direct, iar celelalte revin la webhook.

## Apeluri directe către endpoint

Când AI-ul invocă un instrument care are un `endpoint`, ThunderPhone trimite
o solicitare către URL-ul dumneavoastră:

### Antete de solicitare

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

Antetele personalizate din `endpoint.headers` sunt întotdeauna incluse
literal, plus două antete cu spațiu de nume ThunderPhone:

* `X-ThunderPhone-Signature` — HMAC-SHA256 al octeților exacți ai corpului
  solicitării, folosind ca cheie **secretul webhook al organizației**
* `X-ThunderPhone-Call-ID` — ID-ul apelului curent

`Content-Type: application/json` este setat, cu excepția cazului în care `endpoint.headers`
îl suprascrie — un `Content-Type` personalizat are prioritate.

<Warning>
  Semnătura folosește ca cheie secretul webhook la nivel de organizație din
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Dacă organizația dumneavoastră nu a configurat niciodată webhook-ul vechi, nu există
  niciun secret, iar apelurile de instrumente conțin **doar** `X-ThunderPhone-Call-ID` —
  un gestionar care eșuează automat când lipsește o semnătură le-ar respinge.
  Configurați fie webhook-ul vechi pentru a obține un secret, fie introduceți propriul
  secret partajat în `endpoint.headers`.
</Warning>

### Corpul solicitării

Pentru `POST` / `PUT` / `PATCH`, corpul conține **doar** argumentele
instrumentului (fără înveliș), serializate canonic (chei sortate, separatori
compacți):

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

Pentru `GET` / `DELETE`, argumentele sunt trimise ca **parametri de interogare**
iar corpul este gol — semnătura este apoi calculată peste șirul gol de
octeți. Consultați
[Verificarea semnăturilor webhook](/ro/guides/verify-webhook-signatures).

### Răspuns

Returnați un răspuns JSON cu rezultatul instrumentului:

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

Răspunsul este formatat și furnizat AI-ului pentru a continua
conversația. Răspunsurile non-JSON sunt încapsulate ca `{"data": "<text>"}`;
expirările și erorile de conexiune sunt raportate AI-ului ca erori, astfel încât
agentul să poată să își ceară scuze și să continue, în loc să se blocheze.

## Direcționare în modul webhook

Instrumentele **fără** un `endpoint` sunt direcționate către URL-ul webhook
vechi al organizației dumneavoastră ca o solicitare semnată `telephony.tool` (apeluri telefonice) sau `web.tool`
(apeluri web). Spre deosebire de [notificările de audit](/ro/webhooks/events)
livrate către endpoint-uri webhook după execuție, această solicitare **este**
execuția — răspunsul dumneavoastră HTTP este rezultatul instrumentului.

```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` conține `origin_domain` în loc de `from_number` /
`to_number`. Răspundeți cu rezultatul instrumentului ca JSON — același contract
de răspuns ca pentru apelurile directe către endpoint. Solicitarea este semnată cu secretul
webhook al organizației peste corpul brut, la fel ca orice alt webhook.

<Note>
  [Endpoint-urile webhook](/ro/webhooks/endpoints) abonate primesc suplimentar
  o **notificare** neblocantă `telephony.tool` / `web.tool`
  **după** executarea fiecărui instrument (indiferent de calea care l-a executat), inclusiv
  răspunsul instrumentului — utilă pentru piste de audit. Consultați
  [catalogul de evenimente](/ro/webhooks/events).
</Note>

***

## Verificarea semnăturii

Apelurile directe de instrumente sunt semnate în același mod ca webhookurile:

* HMAC-SHA256 peste octeții exacți ai corpului cererii (JSON-ul canonic —
  chei sortate, fără spații suplimentare)
* Folosind secretul webhook al organizației dumneavoastră
* Instrumentele `GET` / `DELETE` semnează șirul de octeți gol

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

Rețetele complete — inclusiv cazul corpului gol și avertismentul privind absența unui secret —
sunt disponibile în [Verificarea semnăturilor webhook](/ro/guides/verify-webhook-signatures).

***

## Exemplu: flux complet de programare

Iată un set de instrumente pentru un sistem complet de programare a întâlnirilor:

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

***

## Bune practici

<AccordionGroup>
  <Accordion title="Scrieți descrieri clare">
    Câmpul `description` ajută AI-ul să înțeleagă **când** să utilizeze instrumentul. Specificați clar ce face și când este potrivit să fie utilizat.
  </Accordion>

  <Accordion title="Gestionați erorile în mod corespunzător">
    Returnați mesaje de eroare pe care AI-ul le poate înțelege: `{"error": "No slots available for that date"}` în locul erorilor 500 generice.
  </Accordion>

  <Accordion title="Păstrați răspunsurile concise">
    Returnați doar informațiile de care AI-ul are nevoie pentru a continua conversația. Încărcăturile utile mari încetinesc timpii de răspuns.
  </Accordion>

  <Accordion title="Utilizați câmpurile obligatorii cu discernământ">
    Marcați câmpurile ca `required` numai atunci când este cu adevărat necesar. AI-ul va cere utilizatorului informațiile obligatorii înainte de a apela instrumentul.
  </Accordion>
</AccordionGroup>

***

## Resurse conexe

<CardGroup cols={2}>
  <Card title="Conexiuni de aplicații" icon="plug" href="/ro/guides/connect-apps">
    Instrumente gestionate de platformă pentru HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets și Cal.com — nu este necesar niciun endpoint.
  </Card>

  <Card title="Servere MCP" icon="server" href="/ro/guides/mcp-servers">
    Atașați un server MCP și permiteți agentului să îi apeleze instrumentele.
  </Card>

  <Card title="Conexiuni API" icon="code" href="/ro/guides/api-connections">
    Integrări REST reutilizabile pe care le puteți atașa agenților.
  </Card>

  <Card title="Verificați semnăturile webhook" icon="shield-check" href="/ro/guides/verify-webhook-signatures">
    Un singur ajutor de verificare pentru webhook-uri și apeluri de instrumente.
  </Card>
</CardGroup>
