# Recipes

> Short, complete examples – shopping list from Home Assistant, calendar import, scanning folder, weekly digest.

Copy, set `LIFEBUTLER_KEY` and the workspace ID, run.

## Shopping list from Home Assistant

`configuration.yaml`:

```yaml
rest_command:
  lifebutler_add_item:
    url: "https://api.lifebutler.io/v1/workspaces/f8Hn3wQz0a/lists/L1st1d/items"
    method: POST
    headers:
      Authorization: !secret lifebutler_auth   # "Bearer lb_live_…"
      Content-Type: application/json
    payload: '{"items": ["{{ item }}"]}'
```

Then call `rest_command.lifebutler_add_item` with `item: Milch` from any automation – a fridge sensor, a button, a voice command. Find the list ID with `GET /workspaces/{id}/lists`. Key scope: `lists:write`.

## Import appointments (Python)

```python
import os, requests

API = "https://api.lifebutler.io/v1"
WS = "f8Hn3wQz0a"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['LIFEBUTLER_KEY']}"

def add(title, start, end, location=""):
    r = s.post(f"{API}/workspaces/{WS}/events",
               json={"title": title, "start": start, "end": end, "location": location})
    r.raise_for_status()
    return r.json()["id"]

add("Elternabend 3b", "2026-11-24T19:30", "2026-11-24T21:00", "Grundschule Am Park")

# All-day, several days: dates, end inclusive
s.post(f"{API}/workspaces/{WS}/events",
       json={"title": "Herbstferien", "allDay": True, "start": "2026-10-26", "end": "2026-10-30"}).raise_for_status()
```

Times without an offset are Berlin time. Key scope: `calendar:write`.

## Scanning folder (Node.js)

Uploads every new PDF from a folder; LifeButler names and analyses it if AI is on.

```js
import { readdir, readFile, rename } from "node:fs/promises";

const API = "https://api.lifebutler.io/v1/workspaces/f8Hn3wQz0a/documents";
const headers = { Authorization: `Bearer ${process.env.LIFEBUTLER_KEY}`, "Content-Type": "application/pdf" };

for (const name of await readdir("scans")) {
  if (!name.endsWith(".pdf")) continue;
  const res = await fetch(`${API}?fileName=${encodeURIComponent(name)}`, {
    method: "POST", headers, body: await readFile(`scans/${name}`),
  });
  if (res.ok || res.status === 409) await rename(`scans/${name}`, `scans/done/${name}`); // 409 = already stored
  else console.error(name, res.status, await res.json());
}
```

Key scope: `documents:write`.

## Weekly digest (n8n, Make, cron)

1. `GET /workspaces/{id}/events?from=<monday>&to=<sunday>` – the week's appointments, series expanded.
2. `GET /workspaces/{id}/tasks?status=open` – open tasks, by due date.
3. Format and send it by e-mail or chat.

Key scopes: `calendar:read`, `tasks:read`.

## Ask the butler and let it act

```bash
curl -X POST https://api.lifebutler.io/v1/workspaces/f8Hn3wQz0a/butler \
  -H "Authorization: Bearer $LIFEBUTLER_KEY" -H "Content-Type: application/json" \
  -d '{"question": "Wir grillen Samstag mit 8 Leuten. Setz alles auf die Einkaufsliste und erinnere mich Freitag ans Fleisch.", "apply": true}'
```

```json
{
  "answer": "Ich habe 9 Dinge auf die Einkaufsliste gesetzt und dich für Freitag ans Fleisch erinnert.",
  "actions": [ { "type": "addListItems", "listName": "Einkauf", "items": [ … ] }, { "type": "createTask", "title": "Fleisch beim Metzger abholen", "date": "2026-11-20", … } ],
  "applied": 2,
  "credits": 2
}
```

Without `apply`, the actions are only proposals you can show or create yourself. Key scope: `butler`.
