Darstellung
Kassenverwaltung – Vollständige API-Referenz
Fach-API für die PC-Kasse: Kasse anlegen, Schicht öffnen und schließen, Bon, Einlage und Entnahme, Kassensturz und Storno. Basis ist https://core-backend.reybex.com/api (Staging: https://io-staging-partner.reybex.com/api). Authentifizierung wie im API: --header "authorization: Basic $TOKEN".
Der Bon ist ein Verkaufsbeleg. Speichern, Positionen und Preise stehen unter Auftragsverwaltung. Artikel unter Artikelstamm-Verwaltung, der Laufkunde unter Kunden- und Lieferantenverwaltung.
Der schreibende Weg der Kasse ist POST /api/cashRegister/. Verknüpfungen an diesem Aufruf werden per id gelesen. Ein Suchschlüssel reicht dort nicht.
1. Grundlagen
| Objekt | Rolle |
|---|---|
CashRegister | Kasse mit Lager, Laufkunde, Belegarten und Preisquelle |
CashClose | Offene oder abgeschlossene Schicht |
CashMoveReason | Grund für Einlage, Entnahme und Differenz |
CashBalance | Gezählter Kassensturz |
SalesHead | Bon, an der Kasse ein Verkaufsbeleg |
Die Zahlen in den Beispielen sind Beispiel-Ids eines Mandanten. 9001 ist die Kasse, 30001 der Laufkunde KD-1000, 7001 das Lager HAUPT, 610 die Barzahlart, 501 der Benutzer.
1.1 Antwort- und Fehlerformat
Lesen einer Kasse liefert den Datensatz direkt. Listen kapseln data und meta.
| Situation | Körper |
|---|---|
| Kasse nicht gefunden | cashRegister.not.found |
| Zahlart der Rückgabe ist nicht bar | cashRegister.paymentType.isCash.error |
| Rechnungsart ist keine Rechnung | cashRegister.invoiceDocType.isInvoice.error |
| Auftragsart ist kein Auftrag | cashRegister.orderDocType.isOrder.error |
| Stornoart ist keine Gutschrift | cashRegister.cancelDocType.isCreditnote.error |
Lieferart hat nicht die Bewegungsart 327 | cashRegister.deliveryDocType.stockMoveType.moveTypeCode.error |
| Kein Laufkunde | cashRegister.customer.empty.error |
| Keine offene Schicht | cashRegister.endCashClose.cashClose.empty.error |
| Schicht schon geschlossen | cashRegister.cashClose.isClosed.error |
| Fehlende Anmeldung | HTTP 401 |
2. Kasse anlegen
POST /api/cashRegister/ legt an, wenn keine id im Body steht. Jede Verknüpfung ist { "id": … }. Leere Objekte werden zu null.
Response: { "id": 9001, "isExternal": false }
Bei isExternal true und ohne bestehende Schicht legt das Speichern eine Schicht mit Startbetrag 0 an.
2.1 Felder
| Feld | Bedeutung |
|---|---|
name | Name der Kasse |
customer | Laufkunde, per id. Ohne ihn entsteht kein neuer Bon |
warehouse | Lager der Kasse |
currency | Währung. Sonst die Hauswährung des Bons |
isGrossPrice | Bon startet brutto. Standard true |
priceFrom | Preisquelle, siehe unten |
invoiceDocType | Rechnung (isInvoice) |
orderDocType | Auftrag (isOrder) |
deliveryDocType | Bon aus einem Auftrag. Die Belegart ist eine Rechnung und die Bewegungsart ist 327 |
cancelDocType | Storno, eine Gutschrift (isCreditnote) |
paymentType | Rückgabe-Zahlart, muss bar sein (isCash) |
paymentTypes | Zahlarten an der Kasse. Die erste bare Zahlart wird der Bon-Zahlart |
cashMoveReasons | Gründe für Einlage und Entnahme |
numberRanges | Nummernkreis |
profitCenter, salesDepartment | Profitcenter und Abteilung. Weicht die Abteilung vom Benutzer ab, gilt die Abteilung des Benutzers |
account | FiBu-Konto |
dontPrint | Bon nicht drucken |
isVoucherPrint | Gutschein drucken |
checkPrinter, invoicePrinter | Bondrucker und Rechnungsdrucker, per id |
footer, address | Fußtext und Adresse auf dem Bon |
cashDrawerPassword | Passwort der Kassenschublade. Wird verschlüsselt gespeichert |
sendInvoiceAsEmail | Rechnung per E-Mail |
isExternal | Externe Kasse. Öffnet beim Speichern eine Schicht, wenn keine existiert |
isDelete | Logisch gelöscht |
priceFrom:
| Code | Preis |
|---|---|
default | Sales standart |
salesPrice | VK-Preis Netto |
salesPriceGross | VK-Preis Brutto |
cashRegisterPrice | Kassenpreis |
2.2 Kasse mit Laufkunde
Zuerst Laufkunde, Lager, Rechnungsart, Auftragsart und Barzahlart lesen. Dann:
json
{
"name": "Kasse 1",
"customer": { "id": 30001 },
"warehouse": { "id": 7001 },
"currency": { "id": 1 },
"isGrossPrice": true,
"priceFrom": "salesPriceGross",
"invoiceDocType": { "id": 4201 },
"orderDocType": { "id": 4202 },
"paymentType": { "id": 610 },
"paymentTypes": [{ "id": 610 }],
"dontPrint": false
}4201 ist eine Rechnungs-Belegart, 4202 eine Auftrags-Belegart, 610 eine Barzahlart, 1 die Währung EUR.
2.3 Kasse mit Auftragsbon
Der Bon aus einem offenen Auftrag braucht eine Liefer-Belegart, die zugleich Rechnung ist und die Bewegungsart 327 trägt.
json
{
"id": 9001,
"deliveryDocType": { "id": 4203 },
"cancelDocType": { "id": 4204 }
}4203 ist diese Lieferart, 4204 eine Gutschrift für den Storno.
2.4 Lesen und löschen
GET /api/cashRegister/9001 liest eine Kasse. Ohne Id ist es die Liste.
Auswahl des angemeldeten Benutzers: GET /api/cashRegister/select.
Löschen ist logisch.
DELETE /api/cashRegister/9001 antwortet { "id": 9001 }.
Mehrere Kassen: POST /api/cashRegister/deleteCashRegisters
json
{ "ids": [9001, 9002] }Response: { "ids": [9001, 9002] }
Eine unbekannte Id wird ausgelassen.
Kunde der Kasse: GET /api/cashRegister/customer/30001.
Finanzpositionen: GET /api/cashRegister/finItemsList. Abschlussliste: GET /api/cashRegister/cashCloseList.
3. Bewegungsgrund
POST /api/cashMoveReason/
json
{
"name": "Einlage",
"code": "EINLAGE",
"description": "Wechselgeld",
"finDocType": { "id": 7701 },
"account": { "id": 88001 }
}7701 ist die FiBu-Belegart, 88001 das Konto. finDocType.finPostway entscheidet die Richtung der Buchung: gesetzt ist Zugang, sonst Abgang.
Response: { "id": 9201 }
Lesen: GET /api/cashMoveReason/9201. Ohne Id die Liste aller Gründe.
Den Grund an der Kasse zuordnen, indem cashMoveReasons beim Speichern der Kasse die Ids enthält. Eine Änderung ohne diese Liste leert die Zuordnung.
4. Schicht
Ohne offene Schicht liefert der Bon die Aufforderung, eine Kasse zu wählen (showCashRegisterSelect). Eine zweite offene Schicht derselben Kasse bricht ab: cashRegister.has.open.cash.closes.
4.1 Öffnen
POST /api/cashRegister/startCashClose
id ist die Kasse. amount ist der gezählte Startbestand. currentAmount ist der bisherige Bestand. Die Differenz currentAmount - amount wird gebucht, wenn sie nicht 0 ist. Dafür ist cashMoveReasonId Pflicht.
json
{
"id": 9001,
"amount": 200,
"currentAmount": 200
}Response
json
{
"finHeadId": null,
"cashCloseId": 9101,
"checkPrinter": {}
}9101 ist die offene Schicht. Ist schon eine Schicht offen, wird ihre Id zurückgegeben und der Benutzer der Kasse gesetzt.
Mit Differenz, zum Beispiel 20 EUR mehr in der Lade als der rechnerische Bestand:
json
{
"id": 9001,
"amount": 220,
"currentAmount": 200,
"cashMoveReasonId": 9201
}Fehlt der Grund bei einer Differenz: cashRegister.startCashClose.cashMoveReason.empty.error. Fehlt eine Barzahlart an der Kasse: paymentType.isCash.not.found.
4.2 Stand vor dem Abschluss
GET /api/cashRegister/endCashCloseData/9001
json
{
"cashRegister": {
"id": 9001,
"name": "Kasse 1",
"amount": 200,
"currentCashCloseId": 9101
},
"cashMoveReasons": []
}amount ist der rechnerische Bestand. cashMoveReasons sind die Gründe dieser Kasse. Keine offene Schicht: cashRegister.endCashClose.cashClose.empty.error.
4.3 Schließen
POST /api/cashRegister/endCashClose
id ist die Kasse. currentCashCloseId ist die offene Schicht. amount ist der rechnerische Betrag, currentAmount der gezählte Endbestand. Eine Differenz braucht cashMoveReasonId.
json
{
"id": 9001,
"currentCashCloseId": 9101,
"amount": 200,
"currentAmount": 198,
"cashMoveReasonId": 9202
}9202 ist der Grund Entnahme. Die Schicht erhält endDate und endAmount.
Response: finHeadId, cashCloseId, checkPrinter, invoicePrinter.
Schon geschlossen: cashRegister.cashClose.isClosed.error.
5. Bon
GET /api/cashRegister/sell/{id}/{refSalesHeadId}
| Pfad | Wirkung |
|---|---|
undefined / undefined | Neuer Bon aus dem Laufkunden. Die Antwort ist die Verkaufssicht, noch ohne gespeicherte id |
undefined / 510100 | Offener Auftrag 510100 wird auf die Lieferart der Kasse kopiert |
510200 / undefined | Liest den vorhandenen Bon 510200 |
Der neue Bon übernimmt Laufkunde, Währung, Bruttopreis, Abteilung, Profitcenter und die erste bare Zahlart. Speichern der Positionen erfolgt mit POST /api/salesHead/. Die Kasse und die Schicht stehen dann am Beleg.
Ohne offene Schicht kommt showCashRegisterSelect true. Ohne Laufkunde: cashRegister.customer.empty.error. Ohne Rechnungsart: cashRegister.docType.empty.error.
5.1 Auftrag an der Kasse
510100 muss ein Auftrag sein (isOrder) und den Status 0 haben. Die Kasse braucht deliveryDocType.
GET /api/cashRegister/sell/undefined/510100
Kein Auftrag: cashRegister.order.empty.error. Falsche Belegart: cashRegister.order.docType.error. Status nicht offen: cashRegister.order.status.error. Fehlende Lieferart: cashRegister.deliveryDocType.empty.error.
5.2 Geteilten Auftrag abschließen
GET /api/cashRegister/endSplitOrder?id=510100
Der Auftrag gehört zu einer Kasse, der bezahlte Betrag ist 0 und mindestens eine Position ist ein Teilauftrag (isSplitOrder). Es entsteht der Lieferbeleg der Kasse.
Response: { "id": 510210, "docNumber": "RG-10021" }
Ohne Kasse: endSplitOrder.cashRegister.not.found.error. Ohne Lieferart: endSplitOrder.deliveryDocType.not.found.error. Der Auftrag erfüllt die Bedingungen nicht: endSplitOrder.invalid.order.
5.3 Storno
POST /api/cashRegister/cancelSalesHead
json
{
"id": 510200,
"paymentTypeId": 610
}id ist der Bon. paymentTypeId ist die Zahlart der Rückzahlung.
Response
json
{
"id": 510220,
"orderId": 510100,
"checkPrinter": "Bondrucker",
"invoicePrinter": "Rechnung"
}id ist der Stornobeleg. orderId ist der zugehörige Auftrag, wenn der Bon aus einem Auftrag kam. Die Lagerbuchung dieses Auftrags wird gegengebucht.
6. Einlage, Entnahme, offene Posten
6.1 Kassenbewegung
POST /api/cashRegister/bookCashMove schreibt einen FiBu-Beleg. cashRegister.id ist Pflicht. Jede Position braucht paymentType. Fehlt dort die Id, wird die Barzahlart der Kasse eingesetzt.
json
{
"cashRegister": { "id": 9001 },
"finDocType": { "id": 7701 },
"isGeneral": true,
"items": [
{
"amount": 50,
"description": "Wechselgeld",
"account": { "id": 88001 },
"paymentType": { "id": 610 }
}
]
}Response: { "id": 93001, "checkPrinter": {} }
93001 ist der FiBu-Beleg. Keine Barzahlart: paymentType.isCash.not.found.
6.2 Offene Posten zahlen
Liste: GET /api/cashRegister/finOpenItemsToPay.
Zahlung: POST /api/cashRegister/payInvoice
id ist die Kasse. finOpenItems sind die Posten mit id oder salesHead_hid und amount. paymentTypes sind die Zahlarten mit Betrag. Mindestens eine Zahlart oder ein Gutschein.
json
{
"id": 9001,
"finOpenItems": [
{ "salesHead_hid": 510200, "amount": 25.8, "cashDiscount": 0 }
],
"paymentTypes": [
{ "id": 610, "amount": 25.8 }
]
}Response: id und docNumber des Zahlungsbelegs sowie checkPrinter.
Keine Posten: cashRegister.payInvoice.finOpenItems.empty.error. Weder Zahlart noch Gutschein: cashRegister.payInvoice.paymentTypes.empty.error.
Gutscheine stehen in coupons mit batchnum. Der Gutschein-Code muss als Zahlart existieren.
Erreicht die Zahlung den Belegbetrag, ist der Beleg voll bezahlt. Darunter ist er teilweise bezahlt.
6.3 Kassenschublade
POST /api/cashRegister/openCashDrawer
json
{
"id": 9001,
"cashDrawerPassword": "1234"
}Ohne hinterlegtes Passwort öffnet der Aufruf direkt. Mit Passwort muss es übereinstimmen, sonst cashRegister.cashDrawer.password.incorect. Ohne Bondrucker: cashRegister.checkPrinter.not.set. Unbekannte Kasse: cashRegister.not.set.
Die Antwort enthält printerName, format CASHDR und die Druckeransteuerung.
Zahlart für die Kasse umschalten: GET /api/cashRegister/togglePaymentTypeIsCashRegister?id=610. Der Schalter isCashRegister wechselt. Antwort { "success": true }.
7. Kassensturz
POST /api/cashBalance/ zählt Münzen und Scheine. cashRegister per id. amount ist die Summe. Jede Stückelung hat amount als Stückzahl und worth als Wert. totalAmount der Zeile ist Stück mal Wert.
json
{
"name": "Zählung Mittag",
"cashRegister": { "id": 9001 },
"amount": 200,
"items": [
{ "amount": 10, "worth": 10, "totalAmount": 100 },
{ "amount": 4, "worth": 20, "totalAmount": 80 },
{ "amount": 20, "worth": 1, "totalAmount": 20 }
]
}Response: { "id": 94001 }
Der Aufruf speichert zusätzlich den rechnerischen Bestand als cashRegisterAmount und die vorherige Zählung als previuos.
Lesen: GET /api/cashBalance/94001. Die Liste: GET /api/cashBalance/cashBalanceList.
8. Ablauf
- Laufkunde anlegen, siehe Kasse.
- Kasse mit Laufkunde, Lager und Rechnungsart speichern.
- Schicht mit dem Wechselgeld öffnen.
- Bon holen:
GET /api/cashRegister/sell/undefined/undefined. - Positionen mit
POST /api/salesHead/speichern. - Am Ende den gezählten Bestand schließen.
Ein offener Auftrag wird mit GET /api/cashRegister/sell/undefined/{auftragsId} an die Kasse geholt. Der Storno läuft über POST /api/cashRegister/cancelSalesHead.
9. TSE
POST /api/fiskaly/connect verbindet die Kasse mit der TSE. Die Kassen-Id muss im Körper stehen, sonst fiskaly.connect.cashRegister.id.not.found. Unbekannte Kasse: fiskaly.connect.cashRegister.not.found. Schon verbunden: fiskaly.connect.fiskalyTssClient.already.connected. Der Körper trägt außerdem countryCode, email, isLive und die TSE-Felder fiskalyTssId, fiskalyTssClientId, fiskalyTssApiId, fiskalyTssState, fiskalyTssAdminPin, fiskalyTssAdminPuk, fonBenutzerId, fonTeilnehmerId und fonPin.
Abschluss hochladen: POST /api/fiskaly/cashClose mit cashCloseId. Fehlt die Id: fiskaly.uploadCashClose.cashCloseId.not.found. Unbekannter Abschluss: fiskaly.uploadCashClose.cashClose.not.found. Ohne Endedatum: fiskaly.uploadCashClose.cashClose.endDate.not.set. Keine TSE-Kasse: fiskaly.uploadCashClose.fiskalyCashRegister.not.found. Schon hochgeladen: fiskaly.cashClose.isUploaded.error. Offene Bons: fiskaly.cashClose.sales.not.uploaded.error. Noch offen beim Verbinden: fiskaly.cashClose.open.error.
Organisation löschen: DELETE /api/fiskaly/organization/{id}. Fehlt sie: fiskalyOrganization.not.found. Ohne API-Schlüssel: fiskaly.auth.api_key.not.found oder fiskaly.auth.api_secret.not.found.
Transaktion lesen und anlegen: GET /api/fiskalyTransaction/{id} und POST /api/fiskalyTransaction/. Beenden: PUT /api/fiskalyTransaction/.
10. Endpoint-Katalog
| Methode | Pfad | Bedeutung |
|---|---|---|
GET | /api/cashRegister/{id} | Eine Kasse oder die Liste |
POST | /api/cashRegister/ | Anlegen und ändern. Verknüpfungen per id |
DELETE | /api/cashRegister/{id} | Logisch löschen |
POST | /api/cashRegister/deleteCashRegisters | Mehrere Kassen, Body ids |
GET | /api/cashRegister/select | Kasse des Benutzers |
GET | /api/cashRegister/sell/{id}/{refSalesHeadId} | Bon lesen, neu anlegen oder Auftrag übernehmen |
GET | /api/cashRegister/customer/{id} | Kunde |
GET | /api/cashRegister/finItemsList | Finanzpositionen |
GET | /api/cashRegister/cashCloseList | Abschlüsse |
POST | /api/cashRegister/startCashClose | Schicht öffnen |
GET | /api/cashRegister/endCashCloseData/{id} | Bestand und Gründe vor dem Abschluss |
POST | /api/cashRegister/endCashClose | Schicht schließen |
POST | /api/cashRegister/bookCashMove | Einlage oder Entnahme |
GET | /api/cashRegister/finOpenItemsToPay | Offene Posten |
POST | /api/cashRegister/payInvoice | Offene Posten zahlen |
POST | /api/cashRegister/cancelSalesHead | Bon stornieren |
POST | /api/cashRegister/openCashDrawer | Schublade öffnen |
GET | /api/cashRegister/togglePaymentTypeIsCashRegister | Zahlart für die Kasse umschalten, Query id |
GET | /api/cashRegister/endSplitOrder | Teilauftrag abschließen, Query id |
GET | /api/cashMoveReason/{id} | Ein Grund oder die Liste |
POST | /api/cashMoveReason/ | Grund speichern |
GET | /api/cashBalance/{id} | Ein Kassensturz |
GET | /api/cashBalance/cashBalanceList | Zählliste |
POST | /api/cashBalance/ | Kassensturz speichern |
POST | /api/fiskaly/connect | TSE verbinden |
DELETE | /api/fiskaly/organization/{id} | Organisation löschen |
POST | /api/fiskaly/cashClose | Abschluss hochladen, cashCloseId |
GET | /api/fiskalyTransaction/{id} | Eine Transaktion |
POST | /api/fiskalyTransaction/ | Transaktion anlegen |
PUT | /api/fiskalyTransaction/ | Transaktion beenden |
11. Häufige Fehler
| Situation | Ursache |
|---|---|
cashRegister.customer.empty.error | Kein Laufkunde an der Kasse |
cashRegister.docType.empty.error | Keine Rechnungsart |
cashRegister.not.found | id der Kasse unbekannt |
cashRegister.has.open.cash.closes | Es ist schon eine Schicht offen |
cashRegister.cashClose.isClosed.error | Die Schicht ist bereits zu |
cashRegister.startCashClose.cashMoveReason.empty.error | Differenz ohne cashMoveReasonId |
paymentType.isCash.not.found | Keine Barzahlart |
cashRegister.paymentType.isCash.error | Die Rückgabe-Zahlart ist nicht bar |
cashRegister.deliveryDocType.stockMoveType.moveTypeCode.error | Die Auftrags-Lieferart hat nicht die Bewegungsart 327 |
cashRegister.order.status.error | Der Auftrag ist nicht offen |
cashRegister.order.docType.error | Der Beleg ist kein Auftrag |
cashRegister.payInvoice.finOpenItems.empty.error | Zahlung ohne Posten |
cashRegister.payInvoice.paymentTypes.empty.error | Weder Zahlart noch Gutschein |
cashRegister.cashDrawer.password.incorect | Schubladen-Passwort stimmt nicht |
| Bon bleibt ungespeichert | sell/undefined/undefined liefert die Vorlage. Speichern erfolgt über POST /api/salesHead/ |
| Verknüpfung bleibt leer | An POST /api/cashRegister/ wurde ein Suchschlüssel statt id gesendet |
fiskaly.connect.cashRegister.id.not.found | connect ohne Kassen-Id |
fiskaly.connect.cashRegister.not.found | Die Kasse gibt es nicht |
fiskaly.connect.fiskalyTssClient.already.connected | Die Kasse ist schon verbunden |
fiskaly.uploadCashClose.cashCloseId.not.found | cashClose ohne cashCloseId |
fiskalyOrganization.not.found | Organisations-Id unbekannt |
fiskaly.auth.api_key.not.found | API-Schlüssel der TSE fehlt |