Für Kassensysteme, Warenwirtschaft und alles, was Daten liefert oder abholt.
Basisadresse https://api.bum2.fun/api/v1
Alle Antworten sind JSON in UTF-8. Es gibt keinen CORS-Kopf: das hier ist eine Maschinenschnittstelle, und ein Schlüssel, den ein Browser mitschickt, steht im Quelltext einer Webseite.
Jeder Aufruf braucht einen API-Schlüssel im Kopf
Authorization. Erzeugt wird er im Portal unter
Einstellungen → API-Schlüssel.
curl https://api.bum2.fun/api/v1/artikel \
-H 'Authorization: Bearer ak_…'
Der Schlüssel bestimmt den Tenant.
Er steht in keinem Aufrufparameter und lässt sich nicht wählen. Wer einen Schlüssel hat, sieht die Daten des Tenants, zu dem er gehört — und keine anderen.
Der Schlüssel wird einmal angezeigt und danach nie wieder; gespeichert ist nur sein SHA-256-Hash. Geht er verloren, legt man einen neuen an und sperrt den alten. Ein Schlüssel kann lesen oder lesen und schreiben — eine Auswertung, die Zahlen abholt, braucht das Schreibrecht nicht.
Nicht als Abfrageparameter mitgeben: der stünde in jedem Zugriffsprotokoll des Webservers, in jedem Proxy und in der Browserhistorie.
Sechs Objekte, in dieser Reihenfolge aufeinander aufbauend. Preise, Bestände und Verkäufe verweisen auf Artikel und Standorte — die müssen also zuerst da sein.
| Pfad | Objekt | Zweck |
|---|---|---|
/api/v1/store |
Standorte | Betriebe, Filialen, Restaurants. Muss VOR Preisen und Beständen hochgeladen werden — die verweisen darauf. |
/api/v1/artikel |
Artikel | Der Artikelstamm. Preise und Bestände kommen in eigenen Dateien — ein Artikel kostet je Standort verschieden. |
/api/v1/preis |
Preise | Welcher Artikel kostet an welchem Standort wie viel. Ein Artikel ohne Zeile hier ist an diesem Standort nicht im Angebot. |
/api/v1/bestand |
Bestände | Momentaufnahme je Artikel und Standort. Keine Historie — ein neuer Upload ersetzt den Stand. |
/api/v1/kunde |
Kunden | Stammkunden. Für die Gastronomie meist zweitrangig, für den Handel die Grundlage jeder Kundenauswertung. |
/api/v1/verkauf |
Verkäufe | Bons und ihre Positionen. EINE ZEILE JE POSITION — ein Bon mit drei Artikeln steht dreimal darin, jedes Mal mit derselben Bonnummer. Ohne diese Daten gibt es keine Auswertung, keine ABC-Analyse und keine Prognose. |
GET /api/v1/artikel?limit=100&offset=0
GET /api/v1/artikel/100-001
limit geht bis 1000 (Vorgabe 100). Einzeln lesbar sind nur
Objekte mit eigener Nummer: store, artikel, kunde, verkauf.
Preis und Bestand hängen an Artikel und Standort und haben keine
eigene — sie kommen über den Artikel.
POST /api/v1/verkauf
Content-Type: application/json
{"daten": [
{"bonnummer": "2026-0001", "zeitpunkt": "2026-08-15 19:42",
"storenummer": "RIVA", "artikelnummer": "100-001",
"menge": 2, "einzelpreis": 33.00}
]}
Alles oder nichts.
Ist eine Zeile fehlerhaft, wird keine geschrieben, und die Antwort nennt die betroffenen Zeilen einzeln. Der Gegenentwurf — gute Zeilen übernehmen, schlechte melden — hinterlässt einen halb übertragenen Bon, und niemand weiss hinterher, welche Hälfte.
Über die API wird ergänzt und aktualisiert, nie stillgelegt. Ein Vollabgleich, der fehlende Sätze abschaltet, bleibt der Upload-Seite im Portal vorbehalten.
Der Grund ist die Betriebsart: eine Kasse schickt Teilmengen — den Umsatz
einer Schicht, die geänderten Preise von heute. Was darin fehlt, ist
nicht abgeschafft. Würde die API stilllegen, was sie nicht sieht, legte
der erste Aufruf einer Kasse das halbe Sortiment still, und die Antwort
wäre ein freundliches 200.
Aus derselben Beschreibung wie die Excel-Vorlagen. Mit Pflicht gekennzeichnete Felder müssen in jedem Datensatz stehen.
/api/v1/store| Feld | Typ | Beispiel | Hinweis |
|---|---|---|---|
nummer
Pflicht |
text | RIVA |
Eindeutiges Kürzel, z. B. RIVA. Unveränderlich — es verbindet alle anderen Dateien mit diesem Standort. |
name
Pflicht |
text | Riva |
Wie der Standort im Haus heisst. |
typ
|
auswahl filiale · restaurant · hotel · online · lager · sonstige
|
restaurant |
Leer = filiale. |
strasse
|
text | Ketschauerhofstr. 1 |
|
plz
|
text | 67146 |
Als TEXT eintragen — führende Nullen gehen sonst verloren. |
ort
|
text | Deidesheim |
|
land
|
text | DE |
Zwei Buchstaben nach ISO 3166, z. B. DE, AT, CH. |
waehrung
|
text | EUR |
Leer = EUR. Gilt für alle Preise dieses Standorts. |
/api/v1/artikel| Feld | Typ | Beispiel | Hinweis |
|---|---|---|---|
nummer
Pflicht |
text | 100-001 |
Die Artikelnummer aus deinem System. Sie verbindet Preise, Bestände und Verkäufe mit diesem Artikel. |
bezeichnung
Pflicht |
text | 2023 Riesling „Herrgottsacker" |
|
warengruppe
|
text | Wein Flasche weiß |
Frei wählbar, aber EINHEITLICH schreiben — „Wein weiss" und „Weisswein" sind zwei Gruppen. |
hersteller
|
text | Reichsrat von Buhl |
|
ean
|
text | 4006381333931 |
Als TEXT eintragen, sonst macht Excel 4,00612E+12 daraus. |
basiseinheit
|
text | FL |
Leer = ST. Sonst FL, KG, L, PORTION … |
gewicht
|
zahl | 1,25 |
In KILOGRAMM, immer. 750 g sind 0,75 — eine Spalte für die Einheit gibt es bewusst nicht, sonst stehen Gramm und Kilo in derselben Summe. Für Versandkosten und Liefergewicht. |
jahrgang
|
zahl | 2023 |
Nur bei Wein. Derselbe Wein ist 2019 ein anderer Artikel als 2020. |
status
|
auswahl aktiv · auslaufend · gesperrt
|
aktiv |
Leer = aktiv. |
beschreibung
|
text | |
/api/v1/preis| Feld | Typ | Beispiel | Hinweis |
|---|---|---|---|
artikelnummer
Pflicht |
text | 100-001 |
Muss in der Artikeldatei vorkommen. |
storenummer
Pflicht |
text | RIVA |
Muss in der Standortdatei vorkommen. |
preis
Pflicht |
zahl | 33,00 |
Bruttoverkaufspreis. Komma oder Punkt, beides geht. |
gueltig_ab
|
datum | 01.03.2026 |
Leer = ab heute. Ein früherer Preis wird zu diesem Zeitpunkt beendet, nicht überschrieben. |
/api/v1/bestand| Feld | Typ | Beispiel | Hinweis |
|---|---|---|---|
artikelnummer
Pflicht |
text | 100-001 |
|
storenummer
Pflicht |
text | RIVA |
|
menge
Pflicht |
zahl | 12 |
Darf 0 sein. Leer ist etwas anderes als 0 und wird abgewiesen. |
einheit
|
text | FL |
Leer = die Basiseinheit des Artikels. |
mindestmenge
|
zahl | 6 |
Ab wann nachbestellt wird. Ohne diesen Wert kann der Assistent nicht sagen, was knapp wird. |
stand
|
datumzeit | 14.08.2026 18:00 |
Zeitpunkt der Zählung. Leer = jetzt. |
/api/v1/kunde| Feld | Typ | Beispiel | Hinweis |
|---|---|---|---|
nummer
Pflicht |
text | K-1001 |
|
name
Pflicht |
text | Bessie Wilhelm |
|
email
|
text | [email protected] |
|
strasse
|
text | Hauptstr. 3 |
|
plz
|
text | 67146 |
Als TEXT — sonst fehlen führende Nullen. |
ort
|
text | Deidesheim |
|
land
|
text | DE |
|
angelegt_am
|
datum | 11.09.2023 |
Seit wann Kunde. Ohne dieses Datum lässt sich Neukundengewinnung nicht auswerten. |
/api/v1/verkauf| Feld | Typ | Beispiel | Hinweis |
|---|---|---|---|
bonnummer
Pflicht |
text | 2026-0001 |
Gleiche Nummer = gleicher Bon. |
zeitpunkt
Pflicht |
datumzeit | 14.08.2026 19:42 |
Datum UND Uhrzeit. Nur ein Datum macht jede Tageszeitauswertung unmöglich. |
storenummer
Pflicht |
text | RIVA |
|
artikelnummer
Pflicht |
text | 100-001 |
|
menge
Pflicht |
zahl | 2 |
|
einzelpreis
Pflicht |
zahl | 33,00 |
Der TATSÄCHLICH bezahlte Preis, nicht der Listenpreis. Sonst ändert sich der Umsatz der Vergangenheit bei jeder Preispflege. |
rabatt
|
zahl | 0 |
Leer = 0. |
kundennummer
|
text | |
Leer = anonym. Im Restaurant der Normalfall. |
storniert
|
ja_nein | nein |
ja/nein. Leer = nein. Stornierte Bons zählen nicht zum Umsatz, bleiben aber sichtbar. |
Nach RFC 9457
(Problem Details) — ein festes Format, damit ein Aufrufer nicht raten
muss: title für Menschen, type zum Verzweigen
im Code, errors für die Zeilen, die nicht durchkamen.
{
"type": "https://api.bum2.fun/fehler/anmeldung",
"title": "Der API-Schlüssel wird nicht angenommen.",
"status": 401
}
| Code | type | Bedeutung |
|---|---|---|
| 401 | …/anmeldung |
Kein oder ungültiger Schlüssel. Ein gesperrter Schlüssel bekommt dieselbe Meldung wie ein erfundener — ein Unterschied verriete, dass es ihn gibt. |
| 403 | …/recht |
Schlüssel darf nur lesen, der Aufruf will schreiben. |
| 404 | …/objekt |
Unbekanntes Objekt. moeglich listet die gültigen. |
| 404 | …/nichtgefunden |
Diese Nummer gibt es in diesem Tenant nicht. |
| 400 | …/daten |
Zeilen fehlerhaft. errors nennt sie mit Zeilennummer. |
| 503 | …/datenbank |
Keine Datenbankverbindung. Später erneut versuchen. |
Eine Sammlung mit allen Aufrufen, erzeugt aus derselben Beschreibung wie diese Seite — sie kann also nicht veralten, solange die Schnittstelle sich nicht ändert.
In Postman: Import → Datei wählen. Danach in der
Sammlung unter Variables den Wert schluessel auf den
eigenen API-Schlüssel setzen; er gilt dann für alle Aufrufe.
| Grösse eines Aufrufs | 16 MB |
Zeilen je POST |
keine feste Grenze — praktisch begrenzt das Zeitlimit |
| Antwortzeit | Cloudflare bricht nach 100 Sekunden ab. Bei sehr vielen Zeilen in Teilmengen schicken. |
| Aufrufe je Minute | derzeit nicht begrenzt |
Die Schnittstelle beschreibt sich selbst — hinter der Anmeldung:
curl https://api.bum2.fun/api/v1/ \
-H 'Authorization: Bearer ak_…'
Der Katalog steht bewusst hinter der Anmeldung. Er
stand einmal davor, und GET /api/v1/ antwortete deshalb mit
200 auch auf einen erfundenen Schlüssel — damit taugte der
Endpunkt nicht mehr zum Prüfen der Einrichtung.