<aside> 💡 Ein AgentSkills-kompatibler Skill für die automatische Erstellung von Bexio-Offerten via API. mit OpenClaw. Ist aber auch für andere agentische Systeme wie Manus anpassbar.
</aside>
<aside> ⚠️ Wichtig: mwst_type: "included" + mwst_is_net: true ist die einzige korrekte Kombination für Schweizer MwSt-Berechnung in Bexio.
</aside>
---
name: bexio-offerten
description: >
Erstellt Offerten in Bexio via API. Umfasst Kontakt suchen oder neu anlegen,
Offerte mit Positionen erstellen, als offen markieren und PDF-Link abrufen.
Unterstuetzt einfache Custom-Positionen sowie Gruppen mit Unterpositionen,
optionale Positionen und Rabatte. Triggerphrasen: Offerte erstellen,
Angebot erstellen, Bexio Offerte, Offerte fuer Firmenname, neues Angebot.
---
# Bexio Offerten
## Setup
1. API Token erstellen auf <https://developer.bexio.com>
2. Token speichern: `read -rs KEY && echo "$KEY" > ~/.credentials/bexio-api-key && chmod 600 ~/.credentials/bexio-api-key`
3. Eigene IDs einmalig ermitteln (siehe references/api.md → IDs ermitteln)
## Workflow
1. **Kontakt klären** → suchen, bestätigen oder neu anlegen
2. **Offerte zusammenstellen** → Blueprint wählen, Positionen anpassen
3. **Offerte erstellen** via Script
4. **Als offen markieren** wenn bereit zum Versenden
Lese `references/api.md` für API-Endpunkte, Feld-IDs und Fallstricke.
Lese `references/blueprints.md` für Positions-Vorlagen.
---
## Phase 1: Kontakt
**Immer zuerst suchen.**
```bash
python3 scripts/bexio.py --search-contact "Firmenname"
Treffer gefunden → vorlegen und bestätigen lassen: «Gefunden: [ID] [Firma] [Ort] [Mail] — ist das der richtige Kontakt?» Erst nach Bestätigung weitermachen.
Kein Treffer → fehlende Angaben erfragen, dann neu anlegen:
POST /contact
{
"contact_type_id": 2,
"name_1": "Firma AG",
"name_2": "Max Muster",
"address": "Strasse 1",
"postcode": "8000",
"city": "Stadt",
"country_id": 1,
"mail": "[email protected]",
"language_id": 1
}
POST /3.0/kb_offer
{
"title": "Leistung – Firma AG",
"contact_id": 123,
"user_id": 1,
"language_id": 1,
"bank_account_id": 1,
"currency_id": 1,
"logopaper_id": 1,
"mwst_type": "included",
"mwst_is_net": true,
"is_valid_from": "YYYY-MM-DD",
"is_valid_until": "YYYY-MM-DD",
"header": "Liebe
# Bexio API – Referenz
## Setup
- **API Token:** <https://developer.bexio.com> (nicht über office.bexio.com)
- **Base URL:** `https://api.bexio.com/3.0`
- **Headers:** `Authorization: Bearer {token}`, `Accept: application/json`, `Content-Type: application/json`
## IDs ermitteln (einmalig)
```bash
# Eigene User-ID
GET /users
# Bank-Accounts
GET /bank_accounts
# Steuersätze (z.B. MwSt 8.1%)
GET /taxes
# Einheiten (z.B. Pauschal, Tag, Stunde)
GET /units
# Konten (Erlöse)
GET /accounts
| Feld | Wert |
|---|---|
| country_id Schweiz | 1 |
| language_id Deutsch | 1 |
| currency_id CHF | 1 |
| contact_type Firma | 2 |
| contact_type Person | 1 |
{
"type": "custom",
"pos": "1",
"is_optional": false,
"amount": 1,
"unit_id": DEINE_EINHEIT_ID,
"tax_id": DEIN_STEUERSATZ_ID,
"title": null,
"text": "<strong>Titel</strong><br /><ul><li>Punkt 1</li></ul>",
"unit_price": 1000,
"discount_in_percent": null,
"account_id": DEIN_ERLOESKONTO_ID
}
{
"type": "group",
"pos": "1",
"is_optional": false,
"text": "<strong>Gruppenname</strong><br /><br />Beschreibung",
"show_pos_nr": true,
"show_pos_prices": true,
"positions": [
{ "type": "custom", "pos": "1.1", ... },
{ "type": "custom", "pos": "1.2", ... }
]
}
{
"type": "text",
"is_optional": false,
"text": "<strong>Wichtig zu wissen</strong><br /><ul><li>...</li></ul>",
"show_pos_nr": false
}
{
"type": "discount",
"text": "Rabattbezeichnung",
"is_percentual": true,
"value": 20
}
POST /kb_offer/{id}/issue # als "offen" markieren
POST /kb_offer/{id}/mark_as_sent # als gesendet markieren
GET /kb_offer/{id}/pdf # PDF-Link abrufen
---