bexio API aus Make und Zapier: was die fertigen Module nicht können
Make und Zapier bieten bexio als fertige App an: ein paar Felder ausfüllen, und die Rechnung steht in der Buchhaltung. In den Community-Foren beider Dienste stehen seit 2023 aber Fragen zu bexio, die ohne Lösung blieben, weil dem Modul ein Feld oder ein Endpunkt fehlt. Ich habe diese Fäden durchgesehen und mit der offiziellen bexio-API-Dokumentation verglichen. Dieser Ratgeber zeigt je Fall, woran es im Forum scheiterte und welches Feld der bexio API den Fall löst. Er beschreibt die Module so, wie die Fragenden sie beschreiben; eigene Erfahrung mit Make oder Zapier steckt nicht darin.
Woher die acht Fälle stammen
Die Fälle kommen aus den öffentlichen Foren community.make.com und community.zapier.com, Fragen von 2023 bis 2025. Jeder Fall ist unten verlinkt. «Ohne Lösung» heisst: Im Faden steht keine Antwort, die der Fragende bestätigt hat, oder die Antwort verweist an den Support. Mehrere Fragende melden dasselbe Muster, teils mit Monaten Abstand. Die Lösung über die API ist jeweils an der Dokumentation belegt; die Pfade stehen so in der Referenz.
Fall 1: Mehrere Positionen in einer Rechnung
Das häufigste Problem. Ein Fragender will in Make mehrere Positionen in eine bexio-Rechnung schreiben; das Modul lehnt die Liste ab, und «Update Invoice» bietet gar keine Position an. In Zapier scheitert dasselbe bei einer Shopify-Bestellung mit mehreren Produkten, bei einer WooCommerce-Bestellung über einen Umweg mit Schleife und Zwischenspeicher, und bei einer Payrexx-Zahlung mit der Meldung, dass die Liste der Beträge nicht gleich lang sei wie die Liste der Artikel; am Ende steht ein Entwurf ohne Positionen mit Summe 0.
In der API ist das kein Sonderfall. POST /2.0/kb_invoice nimmt ein Array positions
entgegen, und die Dokumentation sagt ausdrücklich, dass sich Positionstypen mischen lassen:
KbPositionCustom für freie Zeilen, KbPositionArticle für Artikel aus dem Stamm, dazu
Text-, Zwischensummen-, Rabatt- und Seitenumbruch-Positionen. Eine Rechnung mit zwei Zeilen
sieht so aus:
{
"contact_id": 14,
"user_id": 1,
"mwst_type": 0,
"mwst_is_net": true,
"positions": [
{ "type": "KbPositionArticle", "article_id": 3, "amount": "2", "unit_price": "45.00", "tax_id": 4 },
{ "type": "KbPositionCustom", "text": "Versand", "amount": "1", "unit_price": "9.00", "tax_id": 4 }
]
}
bexio empfiehlt höchstens 150 Positionen beim Anlegen; weitere Zeilen hängt man danach mit
POST /2.0/kb_invoice/{document_id}/kb_position_article oder …/kb_position_custom an.
Versand und Rabatt sind damit gewöhnliche Zeilen, kein Sonderweg.
Fall 2: Dokumentnummer bei Offerten
Ein Zapier-Nutzer kann keine Offerte anlegen:
bexio verlangt document_nr, die Aktion hat kein Feld dafür; ein zweiter Betroffener meldet
sich im selben Faden. Ein anderer findet eine Offerte
über ihre Nummer nicht, obwohl
dieselbe Nummer in einem anderen Werkzeug Treffer liefert.
Die Dokumentation zu POST /2.0/kb_offer erklärt die Regel: document_nr darf nicht gesetzt
werden, wenn in bexio die automatische Nummerierung aktiv ist, und ist Pflicht, wenn sie
abgeschaltet ist. Ein Modul ohne dieses Feld funktioniert also nur bei automatischer
Nummerierung. Wer eigene Nummern führt, setzt sie über die API. Die Suche läuft über
POST /2.0/kb_offer/search mit document_nr als Suchfeld:
[{ "field": "document_nr", "value": "AN-00001", "criteria": "=" }]
Ohne criteria sucht bexio mit «like», also nach Teiltreffern; für eine Nummer ist =
der sichere Weg. Dieselben Suchfelder gibt es für Rechnungen unter POST /2.0/kb_invoice/search.
Fall 3: Steuersatz je Position
Eine Rechnung kommt mit 7.7 % statt 8.1 % in bexio an, und der Steuersatz lässt sich im Modul nicht wählen. Zapier bestätigt im Faden einen Fehlerbericht; der Workaround lautet, den Satz am Produkt in bexio zu hinterlegen.
In der API trägt jede Position ihr Feld tax_id. Die gültigen Werte liefert
GET /3.0/taxes?types=sales_tax&scope=active; genau diesen Aufruf empfiehlt die
Dokumentation, weil auf Offerten, Aufträgen und Rechnungen nur aktive Umsatzsteuern
zulässig sind. Die Antwort nennt je Satz id, code, value und die Jahre, in denen er
gilt. Ein Dienst liest diese Liste einmal und wählt die tax_id nach Prozentsatz, statt eine
Nummer fest einzubauen, die beim nächsten Satzwechsel falsch wird.
Fall 4: Referenz für den Zahlungsabgleich
Ein Fragender legt Rechnungen aus einem Google Sheet an und will die 27-stellige Referenznummer in das Referenzfeld schreiben, damit bexio Zahlungen von der Bank automatisch zuordnet. Zapier legt einen Funktionswunsch an; ein Termin wird nicht genannt.
Die Rechnung in der API hat zwei Referenzfelder. reference ist ein Freitext auf dem
Dokument. api_reference ist laut Dokumentation nur über die API lesbar und änderbar und
dafür gedacht, Verweise auf andere Systeme abzulegen, etwa die Bestellnummer des Shops oder
die Zahlungs-ID des Anbieters; es ist auch ein Suchfeld von POST /2.0/kb_invoice/search.
Die Antwort einer Rechnung enthält zudem qr_invoice_id. Ein Feld, über das man die
Referenz des QR-Zahlteils selbst setzt, beschreibt die Dokumentation nicht.
Wer die Zahlung ohnehin von einem Zahlungsanbieter gemeldet bekommt, braucht den Bankabgleich
dafür nicht: POST /2.0/kb_invoice/{invoice_id}/payment bucht die Zahlung mit date,
value und bank_account_id direkt auf die Rechnung. Die Zahlung steht dann in bexio auf
der Rechnung, und niemand mahnt Kunden, die längst bezahlt haben.
Fall 5: Benutzer bei der Zeiterfassung
Zeiteinträge aus einem Google Sheet sollen in bexio dem richtigen Mitarbeiter gehören. Im Zapier-Modul lässt sich die Benutzer-ID nicht setzen; das Feld wird mit einem Kontakt gefüllt, der Fragende findet keinen Weg.
POST /2.0/timesheet verlangt user_id als Pflichtfeld, dazu client_service_id für die
Leistung, allowable_bill für «verrechenbar» und ein Objekt tracking, entweder als Dauer
(type: duration mit date und duration) oder als Zeitspanne (type: range). Die
Benutzer liefert GET /3.0/users, die Leistungen GET /2.0/client_service. Kontakt und
Projekt sind optional (contact_id, pr_project_id). Ein Eintrag von einer Stunde und
vierzig Minuten:
{
"user_id": 1,
"client_service_id": 1,
"allowable_bill": true,
"contact_id": 2,
"tracking": { "type": "duration", "date": "2026-11-04", "duration": "01:40" }
}
Fall 6: PDF einer Offerte
Ein Make-Nutzer will Offerten als PDF in DocuWare ablegen. Für Rechnungen gibt es ein Modul, für Offerten nicht; der Versuch mit einem HTTP-Aufruf liefert ein PDF, das sich nicht öffnen lässt. Die einzige Antwort verweist auf HTTP-Grundlagen.
GET /2.0/kb_offer/{quote_id}/pdf liefert das Dokument, wahlweise mit oder ohne Briefpapier
(logopaper). Der Punkt, an dem der Fragende scheiterte: Die Antwort ist kein PDF, sondern
JSON mit den Feldern name, size, mime und content, und content enthält die Datei
Base64-kodiert. Erst nach dem Dekodieren liegt eine gültige PDF-Datei vor. Dasselbe gilt für
Rechnungen (/2.0/kb_invoice/{invoice_id}/pdf) und Aufträge (/2.0/kb_order/{order_id}/pdf).
Fall 7: Geänderte Rechnungen erkennen
Der Make-Trigger «Watch Invoices» liefert nach Angabe eines Fragenden keine Datensätze, wenn eine Rechnung nur geändert wird. Ein Antwortender vermutet einen Fehler im Modul, ein zweiter schlägt vor, stattdessen zu suchen.
Die API bietet dafür das Suchfeld updated_at mit Vergleichskriterien. Ein Dienst merkt
sich den Zeitstempel seines letzten Laufs und fragt:
[{ "field": "updated_at", "value": "2026-11-04 06:00:00", "criteria": ">" }]
an POST /2.0/kb_invoice/search?order_by=updated_at_desc. Das Zeitformat entspricht dem,
das bexio in updated_at zurückgibt. So erscheinen neue und geänderte Rechnungen gleich,
etwa ein Statuswechsel auf «bezahlt».
Fall 8: Rechnung aus einer Bestellung
Eine Shopify-Bestellung wird in Make zur bexio-Bestellung; die Rechnung daraus soll ein HTTP-Aufruf erzeugen, weil es kein Modul dafür gibt. Der Aufruf scheitert mit Status 415, während derselbe Aufruf in Postman funktioniert. Der Make-Support bestätigt im Faden ein bekanntes Problem («known issue») und gibt es an die Entwicklung weiter, ohne Termin.
Der Endpunkt ist POST /2.0/kb_order/{order_id}/invoice. Der Body ist optional: Fehlt er,
übernimmt bexio alle Positionen der Bestellung; sonst nennt positions die gewünschten
Zeilen mit id, type und amount. Status 415 bedeutet, dass der Server den Inhaltstyp
der Anfrage nicht annimmt; die Dokumentation verlangt Accept: application/json und JSON
als Body. Ein eigener Dienst setzt die Header selbst und ist nicht davon abhängig, wie ein
Zwischendienst sie weitergibt.
Die acht Fälle im Überblick
| Fall | Im Forum | In der bexio API |
|---|---|---|
| Mehrere Positionen | Liste wird abgelehnt, Entwurf mit Summe 0 | positions in POST /2.0/kb_invoice, gemischte Typen |
| Dokumentnummer | Pflichtfeld fehlt, Suche ohne Treffer | document_nr, Suche mit criteria: "=" |
| Steuersatz | nicht wählbar, falscher Satz | tax_id je Position, Liste aus /3.0/taxes |
| Referenz | Feld fehlt, Funktionswunsch offen | reference, api_reference, Zahlung per …/payment |
| Zeiterfassung | Benutzer nicht setzbar | user_id in POST /2.0/timesheet |
| Offerten-PDF | kein Modul, Datei unlesbar | /2.0/kb_offer/{id}/pdf, content Base64 dekodieren |
| Geänderte Rechnungen | Trigger reagiert nicht | Suche nach updated_at mit > |
| Rechnung aus Bestellung | kein Modul, Status 415 | POST /2.0/kb_order/{id}/invoice |
Dazu kommt ein Risiko, das keinem Feld zuzuordnen ist: Ein Zapier-Nutzer meldet, dass bexio die Client-ID der Zapier-App gesperrt hat und seine Verbindung damit stand. Wer über eine fremde App verbindet, hängt an deren Zulassung; eine eigene App im Developer Portal hängt nur an der eigenen. Wie man sie anlegt, steht im Ratgeber bexio API Token erstellen, die Anmeldung per OAuth 2 im Ratgeber bexio API mit WordPress verbinden.
Wann sich die direkte Anbindung lohnt
Für einen Kontakt aus einem Formular reichen die fertigen Module meist. Sobald Rechnungen mit mehreren Zeilen, eigene Nummern, Steuersätze, Zeiteinträge je Mitarbeiter oder PDFs im Spiel sind, kostet der Umweg über die Zwischenplattform mehr Zeit, als er spart: Jedes fehlende Feld wird zu einem Forenfaden ohne Ende.
Eine Schnittstelle, die direkt mit der bexio API spricht, baue ich zum Festpreis: Sie nennen mir Quellsystem und Ablauf, ich lege den Umfang an Ihren echten Belegen fest, die Anbindung läuft auf eigener Infrastruktur ohne Abo bei einem Dritten, mit Wiederholung bei Fehlern und einem Protokoll, das zeigt, was übertragen wurde. Für HubSpot gibt es die Anbindung fertig: bexio ↔ HubSpot macht aus einem gewonnenen Deal eine Offerte oder Rechnung mit Positionen und meldet den Zahlungsstand zurück. Für alles andere: Kontakt, mit Quellsystem und dem, was heute von Hand läuft.