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

# Benutzerdefinierte Variablen

> Definiere Variablen pro Assistent und füge Live-Werte – aus der API, Kampagnen-Leads, einem eingehenden Webhook oder dem Systemkontext – in Prompts, Begrüßungen und Tools ein

Mit benutzerdefinierten Variablen schreibst du einen Assistenten einmal und personalisierst trotzdem jeden Anruf. Statt einen Namen, einen Termin oder eine Kontonummer fest in den System-Prompt zu schreiben, referenzierst du einen Platzhalter wie `{{customer_name}}` und lieferst den Wert pro Anruf – aus deiner API-Anfrage, einem Kampagnen-Lead, einem eingehenden Anreicherungs-Webhook oder dem eingebauten Systemkontext der Plattform.

## Referenzsyntax

Referenziere eine Variable mit doppelten geschweiften Klammern – das ist die bevorzugte, JSON-sichere Form:

```text theme={null}
Hi {{customer_name}}, I see your appointment is on {{appointment_date}}.
```

Die alte Form mit einfachen Klammern `{customer_name}` wird ebenfalls aufgelöst, allerdings **nur für Schlüssel, die tatsächlich bekannt sind** (eine definierte Variable oder eine Systemvariable). So bleiben literale Klammern – zum Beispiel JSON im Body eines Tools – unangetastet. Jeder Platzhalter mit unbekanntem Schlüssel bleibt unverändert stehen.

## Variablen für einen Assistenten definieren

Jeder Assistent hat eine Liste von Variablendefinitionen. Eine Definition besteht aus:

| Feld            | Erforderlich | Beschreibung                                                                                                                                                                                                                                                              |
| --------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key`           | ja           | Der Bezeichner, der als `{{key}}` verwendet wird. Beginnt mit einem Kleinbuchstaben, danach Kleinbuchstaben, Ziffern und Unterstriche; 1–64 Zeichen (`^[a-z][a-z0-9_]{0,63}$`). Pro Assistent eindeutig. Darf keine reservierte [Systemvariable](#system-variables) sein. |
| `label`         | ja           | Für Menschen lesbarer Name, der im Editor angezeigt wird.                                                                                                                                                                                                                 |
| `description`   | nein         | Notiz, wofür die Variable gedacht ist.                                                                                                                                                                                                                                    |
| `default_value` | nein         | Fallback-Wert, der genutzt wird, wenn zum Zeitpunkt des Anrufs kein Wert übergeben wird.                                                                                                                                                                                  |
| `example`       | nein         | Beispielwert (nur für Editor/Doku, wird nie gesendet).                                                                                                                                                                                                                    |
| `source`        | nein         | Informativer Hinweis: `manual` (Standard), `lead`, `webhook` oder `system`. Steuert UI-Hinweise und das Webhook-Mapping, schränkt aber nicht ein, woher ein Wert tatsächlich kommen kann.                                                                                 |

<Note>
  Schlüssel werden beim Speichern validiert: Ein ungültiges Format, eine Kollision mit einer reservierten Systemvariable, ein doppelter Schlüssel oder ein fehlendes Label werden allesamt abgelehnt.
</Note>

## Wo Variablen ersetzt werden

Werte werden beim Start des Anrufs ersetzt, bevor Modell oder Flow laufen – und zwar in diesen Feldern:

* **System-Prompt** des Assistenten
* **Erste Nachricht** des Assistenten (Begrüßung)
* Flow-Node **`start.greeting`**
* Flow-Node **`agent.instructions`**
* **URL** und Header-**Werte** der Anfrage im Flow-**Tool-Node**

So kann ein Tool-Node `https://app.famulor.de/api/user/orders/{{order_id}}` aufrufen oder `Authorization: Bearer {{api_token}}` mit Werten pro Anruf senden.

## Wertquellen und Priorität

Ein Wert kann aus mehreren Quellen kommen. Beim Start des Anrufs löst der Worker jeden Schlüssel nach dieser Priorität auf, höchste zuerst:

1. **Explizit** – Werte, die direkt mit dem Anruf übergeben werden: über `variables` im API-Aufruf `make-call`, oder die benutzerdefinierten Felder eines Kampagnen-Leads, die auf passende Schlüssel gemappt werden.
2. **Eingehender Variablen-Webhook** – Anreicherung, die beim Start des Anrufs abgerufen wird (siehe [unten](#inbound-variable-webhook)).
3. **Systemvariablen** – von der Plattform aus dem Anrufkontext befüllt.
4. **Standardwert** – der `default_value` aus der Definition.

Ein Platzhalter, der auf keiner Ebene einen Wert bekommt, bleibt unverändert.

### Explizite Werte über die API

```bash theme={null}
curl -X POST https://app.famulor.de/api/user/make-call \
  -H "Authorization: Bearer fam_..." \
  -H "Content-Type: application/json" \
  -d '{
    "assistant_id": "asst_123",
    "to_number": "+493012345678",
    "variables": { "customer_name": "Jordan", "appointment_date": "2026-07-10" }
  }'
```

### Kampagnen-Leads → Variablen

In einer [Kampagne](/campaigns/overview) hat jeder Lead frei definierbare **benutzerdefinierte Felder** (`leads.custom_fields`). Beim Wählen wird das benutzerdefinierte Feld eines Leads auf eine Variable mit dem **gleichen Schlüssel** gemappt. So wird aus einer CSV-Spalte eine Variable:

```csv theme={null}
phone_number,name,customer_name,appointment_date
+493012345678,Jordan,Jordan,2026-07-10
+491701234567,Alex,Alex,2026-07-11
```

Hier befüllen die Spalten `customer_name` und `appointment_date` bei jedem Anruf `{{customer_name}}` und `{{appointment_date}}`. Gib einer Lead-basierten Variable `source: "lead"`, um die Absicht zu dokumentieren.

## Systemvariablen

Diese Schlüssel sind immer verfügbar und werden vom Worker beim Start des Anrufs befüllt. Sie sind reserviert – du kannst keine benutzerdefinierte Variable mit einem dieser Schlüssel anlegen.

| Schlüssel        | Label                | Beschreibung                                                                                   | Beispiel               |
| ---------------- | -------------------- | ---------------------------------------------------------------------------------------------- | ---------------------- |
| `caller_number`  | Anrufernummer        | Die Telefonnummer, von der der Anruf kommt (eingehend) bzw. an die er geht (ausgehend), E.164. | `+493012345678`        |
| `called_number`  | Angerufene Nummer    | Die gewählte Nummer bzw. deine Nummer, die den Anruf empfangen hat, E.164.                     | `+498998765432`        |
| `assistant_name` | Name des Assistenten | Der Name des Assistenten, der den Anruf bearbeitet.                                            | `Reception Bot`        |
| `direction`      | Anrufrichtung        | `inbound`, `outbound` oder `web`.                                                              | `inbound`              |
| `call_id`        | Anruf-ID             | Eindeutige ID dieses Anrufs.                                                                   | `c_a1b2c3`             |
| `date`           | Datum                | Aktuelles Datum beim Start des Anrufs (Zeitzone des Assistenten), `YYYY-MM-DD`.                | `2026-07-05`           |
| `time`           | Uhrzeit              | Aktuelle Uhrzeit beim Start des Anrufs (Zeitzone des Assistenten), `HH:MM`.                    | `14:30`                |
| `datetime`       | Datum & Uhrzeit      | Aktuelles Datum und Uhrzeit beim Start des Anrufs (ISO 8601).                                  | `2026-07-05T14:30:00Z` |
| `weekday`        | Wochentag            | Aktueller Wochentag beim Start des Anrufs.                                                     | `Sunday`               |

## Eingehender Variablen-Webhook

Bei **eingehenden** Anrufen kennst du den Anrufer oft nicht im Voraus. Konfiguriere einen **Variablen-Webhook** am Assistenten (`variable_webhook_url` + `variable_webhook_secret`) – der Worker ruft ihn beim Start des Anrufs auf, um Variablen anzureichern, zum Beispiel um einen Kunden anhand seiner Anrufernummer nachzuschlagen.

### Anfrage

Der Worker sendet einen `POST` mit JSON-Body:

```json theme={null}
{
  "event": "call.variables",
  "assistant_id": "asst_123",
  "call_id": "c_a1b2c3",
  "direction": "inbound",
  "from_number": "+493012345678",
  "to_number": "+498998765432"
}
```

Der rohe Request-Body wird mit HMAC-SHA256 signiert, unter Verwendung des `variable_webhook_secret` des Assistenten, und im Header mitgesendet:

```text theme={null}
X-Famulor-Signature: sha256=<hexdigest>
```

### Antwort

Gib die zu mergenden Variablen zurück:

```json theme={null}
{
  "variables": {
    "customer_name": "Jordan",
    "open_amount": "128.50"
  }
}
```

Diese Werte werden **über** Systemvariablen und Standardwerten gemergt, aber **unter** allen expliziten Dispatch-Werten. Der Aufruf hat ein Timeout von ca. 5 Sekunden; ein Fehlschlag ist nicht kritisch – der Worker protokolliert ihn und macht mit den bereits vorhandenen Werten weiter.

### Native Automation (Alternative)

Statt einer eigenen `variable_webhook_url` kannst du auch eine **Automation** mit dem Trigger **Eingabevariablen einspeisen** (`call.variables`) anlegen, die an den Assistenten gebunden ist. Beim Start des Anrufs führt der Worker diese Automation synchron aus und erwartet eine **Variablen zurückgeben**-Aktion (im gleichen `{ variables: {…} }`-Format). Existiert keine passende aktive Automation, wird als Fallback die klassische Webhook-URL verwendet.

### Signatur verifizieren

<CodeGroup>
  ```js Node.js theme={null}
  import crypto from "node:crypto";

  // rawBody: die exakten empfangenen Bytes, vor JSON.parse
  function verify(rawBody, signatureHeader, secret) {
    const expected =
      "sha256=" +
      crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
    const a = Buffer.from(signatureHeader);
    const b = Buffer.from(expected);
    return a.length === b.length && crypto.timingSafeEqual(a, b);
  }
  ```

  ```python Python theme={null}
  import hmac, hashlib

  # raw_body: die exakten empfangenen Bytes, vor json.loads
  def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
      expected = "sha256=" + hmac.new(
          secret.encode(), raw_body, hashlib.sha256
      ).hexdigest()
      return hmac.compare_digest(expected, signature_header)
  ```
</CodeGroup>

<Warning>
  Berechne den HMAC immer über die **rohen** Bytes des Request-Bodys, nicht über ein neu serialisiertes Objekt – eine erneute Serialisierung kann Whitespace oder die Key-Reihenfolge verändern und damit die Signatur brechen. Verwende einen zeitkonstanten Vergleich.
</Warning>

### Beispielanfrage

```bash theme={null}
curl -X POST https://your-app.example.com/famulor/variables \
  -H "Content-Type: application/json" \
  -H "X-Famulor-Signature: sha256=6d3a...e1f0" \
  -d '{
    "event": "call.variables",
    "assistant_id": "asst_123",
    "call_id": "c_a1b2c3",
    "direction": "inbound",
    "from_number": "+493012345678",
    "to_number": "+498998765432"
  }'
```

## API & MCP

* `GET /v1/assistants/{id}/variables` – liest die Variablendefinitionen des Assistenten; Scope `assistants:read`.
* `PATCH /v1/assistants/{id}/variables` – ersetzt die Variablendefinitionen; Scope `assistants:write`.
* MCP-Tools: `get_assistant_variables`, `set_assistant_variables`.

<Tip>
  Die vollständige REST-Referenz findest du unter [docs.famulor.io](https://docs.famulor.io). Nutze `{{key}}` überall dort, wo du einen Wert pro Anruf brauchst, halte Schlüssel in `snake_case` und gib jeder Variable einen sinnvollen `default_value`, damit Anrufe sauber degradieren, wenn eine Quelle fehlt.
</Tip>
