Zum Hauptinhalt springen

Standort-Server REST-API v1

Diese API läuft direkt auf jedem Standort-Server (.NET 8, Repo de.profipos.server) und ist im LAN unter http://<server-ip>:8080 erreichbar. Sie wird live verwendet von allen Endgeräten der Welle-1C-/Welle-2-Domain (Kasse, Kundendisplay, goapp, kitchendisplay, lieferapp, selfservice, werbedisplay).

tipp

Die hier dokumentierten Endpoints wurden mit Build #22 (Commit fb67297b6af, 13.06.2026) auf main ausgerollt. Die ältere Cloud-REST-API v6 für Bestellportal und Onboarding existiert parallel weiter.

Basis-URL

http://<server-ip>:8080/api/v1

Die Server-IP wird typischerweise per UDP-Discovery ermittelt (Magic PROFIPOS-DISCOVER-V6, Port 34567).

Authentifizierung

Die Endpoints sind in zwei Gruppen aufgeteilt:

GruppeAuthEndpoints
SecureBearer-Token (pp_<43-base64url>) im Header Authorization/auth/device/*, /tische/{uuid}, /tische/{uuid}/status
Publickeine (Übergangslösung, wird in einer Folge-Welle abgesichert)Warenkorb, Artikel-Suche, Bondruck, Schublade

Token-Schema, Generierung und Widerruf siehe Geräte-Auth.

Authorization: Bearer pp_xR4dKw9V…

Bei fehlendem oder ungültigem Token antworten Secure-Endpoints mit:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{ "fehler": "unauthorized", "grund": "unbekanntes_oder_abgelaufenes_token" }

Mögliche grund-Werte: kein_bearer_token, ungueltiges_token_format, unbekanntes_oder_abgelaufenes_token, interner_fehler.

JSON-Konvention

  • Server und Client serialisieren konsequent snake_case (per JsonNamingPolicy.SnakeCaseLower global aktiviert).
  • Deserialisierung ist case-insensitive.
  • DTOs brauchen daher keine [JsonPropertyName]-Attribute mehr.

Endpoint-Übersicht

MethodePfadAuthZweck
POST/api/v1/auth/device/loginSecureGeräte-Token mit Server-Status validieren
GET/api/v1/auth/device/meSecureAktueller Geräte-Kontext (Mandant/Standort/Gerät)
GET/api/v1/tische/{uuid}SecureTisch-Detail inkl. aktivem Bon
POST/api/v1/tische/{uuid}/statusSecureTisch-Status setzen (+ MQTT-Publish)
POST/api/v1/bons/{uuid}/positionenPublicPosition zum Warenkorb hinzufügen
PATCH/api/v1/bonpositionen/{uuid}PublicMenge einer Position ändern
DELETE/api/v1/bonpositionen/{uuid}PublicPosition stornieren
GET/api/v1/bons/{uuid}/zahlungenPublicZahlungen zu einem Bon listen
GET/api/v1/bestellungenPublicOffene Bestellungen filtern
GET/api/v1/artikel/suchePublicArtikel-Volltext-Suche
POST/api/v1/bons/{uuid}/druckPublicBon drucken (ESC/POS, TCP/9100)
POST/api/v1/schublade/oeffnenPublicGeldschublade öffnen

Auth-Endpoints

POST /api/v1/auth/device/login

Bestätigt einen Geräte-Token gegenüber dem Server und liefert den aktuellen Kontext. Wird vor allem genutzt, um auf einem frisch provisionierten Gerät zu prüfen, ob der hinterlegte Token noch gültig ist.

Request-Header:

Authorization: Bearer pp_xR4dKw9V…

Response 200:

{
"geraet_uuid": "0f7c…",
"mandant_uuid": "a31e…",
"standort_uuid": "6c91…",
"geraete_typ": "kasse",
"bezeichnung": "Kasse 1 Bar",
"gueltig_am": "2026-06-13T14:22:18Z"
}

GET /api/v1/auth/device/me

Identisch zur Response von /login, aber idempotenter „Wer bin ich?“-Call — wird typischerweise beim App-Start oder Reconnect getriggert.

curl -H "Authorization: Bearer pp_xR4dKw9V…" \
http://10.1.1.20:8080/api/v1/auth/device/me

Tische

GET /api/v1/tische/{uuid}

Liefert Tisch-Detail inkl. aktivem Bon + Positionen.

Response 200:

{
"tisch_uuid": "11ab…",
"raum_uuid": "22cd…",
"nummer": 12,
"name": "Tisch 12",
"status": "belegt",
"kapazitaet": 4,
"aktiver_bon": {
"bon_uuid": "33ef…",
"bon_nummer": 1042,
"summe_brutto": 47.30,
"summe_offen": 47.30,
"eroeffnet_am": "2026-06-13T11:48:02Z"
},
"aktive_positionen": [
{ "position_uuid": "…", "menge": 2, "bezeichnung": "Apfelschorle 0,4l", "einzelpreis": 3.80 },
{ "position_uuid": "…", "menge": 1, "bezeichnung": "Schnitzel Wiener Art", "einzelpreis": 18.90 }
]
}

POST /api/v1/tische/{uuid}/status

Setzt den Tisch-Status und löst ein retained MQTT-Publish auf profipos/{mandant}/{standort}/tisch/{kurz}/status aus.

Request:

{ "status": "belegt" }

Erlaubte Werte: frei, belegt, reserviert, wartung, geparkt.

Response 204 (No Content).


Warenkorb / Bons

POST /api/v1/bons/{uuid}/positionen

Fügt eine neue Position zu einem offenen Bon hinzu. Prüft den Bon-Status und antwortet 409 Conflict, wenn der Bon bereits bezahlt oder storniert ist.

Request:

{
"artikel_uuid": "…",
"menge": 2,
"einzelpreis": 3.80,
"bezeichnung": "Apfelschorle 0,4l",
"kueche_status": "neu",
"bediener_uuid": "…"
}

Response 201:

{
"position_uuid": "44gh…",
"position_nr": 17
}

Die position_nr wird serverseitig via SELECT MAX(position_nr) + 1 ermittelt.

PATCH /api/v1/bonpositionen/{uuid}

Ändert die Menge einer bereits angelegten Position. Triggert RecalcBonSummenAsync (Netto = brutto / (1 + steuersatz/100)).

{ "menge": 3 }

Response 204 bei Erfolg, 404 wenn Position nicht existiert.

DELETE /api/v1/bonpositionen/{uuid}

Storniert eine Position. Hängt einen Storno-Grund + Bediener-UUID per Query-String an:

DELETE /api/v1/bonpositionen/44gh…?bediener=…&grund=Falsch+gebucht

Response 204.

GET /api/v1/bons/{uuid}/zahlungen

Listet alle Zahlungen zu einem Bon (Bar, Karte, Trinkgeld separat).

[
{
"zahlung_uuid": "…",
"zahlungsart": "bar",
"betrag": 50.00,
"trinkgeld": 2.70,
"bezahlt_am": "2026-06-13T12:05:11Z"
}
]

Bestellungen

GET /api/v1/bestellungen

Listet aktive Bestellungen. Default-Filter: status IN ('offen','in_bezahlung','geparkt','lieferung_offen','abholung_offen').

QueryDefaultBeispiel
status(Default-Liste)?status=offen
limit100?limit=50
curl http://10.1.1.20:8080/api/v1/bestellungen?status=geparkt&limit=20

Artikel-Suche

GET /api/v1/artikel/suche

Volltext-Suche mit Boolean-FULLTEXT + LIKE-Fallback. Mindestlänge 2 Zeichen (sonst 400 mit q_mindestens_2_zeichen).

QueryDefault
q— (Pflicht)
limit50
curl "http://10.1.1.20:8080/api/v1/artikel/suche?q=schnitzel&limit=10"

Response 200:

[
{ "artikel_uuid": "…", "bezeichnung": "Schnitzel Wiener Art", "preis_brutto": 18.90, "warengruppe": "Hauptgerichte" },
{ "artikel_uuid": "…", "bezeichnung": "Pommes", "preis_brutto": 4.50, "warengruppe": "Beilagen" }
]

Bondruck

POST /api/v1/bons/{uuid}/druck

Erzeugt einen ESC/POS-Bondruck (40-Zeichen-Zeilen) und sendet ihn per TCP an den angegebenen Drucker (Default-Port 9100).

Request:

{
"drucker_host": "192.168.1.50",
"drucker_port": 9100,
"kopf": "ProfiPOS Cafe",
"fuss": "Vielen Dank!",
"schneiden": true
}

Response 200 mit Bon-Statistik:

{
"bon_nr": 1042,
"zeilen": 18,
"bytes": 740,
"gesendet_an": "192.168.1.50:9100",
"dauer_ms": 87
}

Response 502 bei Druck-Fehler:

{ "fehler": "druck_fehlgeschlagen", "details": "connection refused" }

Stornierte Positionen (kueche_status = "storniert") werden ausgelassen. Werden Rabatt, Trinkgeld oder Steueraufschlüsselung mitgegeben, kommen sie als zusätzliche Zeilen unter die Summe.

POST /api/v1/schublade/oeffnen

Öffnet die Geldschublade über den per ESC/POS angeschlossenen Drucker.

Request:

{ "drucker_host": "192.168.1.50", "drucker_port": 9100 }

Response 204. Sendet intern die Drawer-Kick-Sequenz 1B 70 00 32 FA (Pin 2, On=50 ms, Off=250 ms) — kompatibel mit Epson, Star und generischen ESC/POS-Druckern.


Fehlerformat

{ "fehler": "<kurz_kennung>", "details": "<optional>" }
HTTPfehlerBedeutung
400q_mindestens_2_zeichenSuche zu kurz
401unauthorizedToken fehlt/ungültig (siehe grund)
404nicht_gefundenUUID existiert nicht
409bon_bereits_bezahlt / bon_storniertPosition kann nicht mehr angehängt werden
502druck_fehlgeschlagenESC/POS-Verbindung fehlgeschlagen

Verwandte Themen