Skip to content

Cash drawer shifts

Open Cash drawer for a property, enter the opening float in its currency, then record cash payments/refunds in the usual reservation folio. The server links each new cash posting to the open shift. The drawer shows the expected count and linked cash activity. Enter the physical count to close it; a difference above the property’s threshold requires a reason. Refresh and recount after a stale-version conflict. Reload retains both open and closed shifts. History opens a report with the float, expected/declared/difference, actors, times and movements. Use Older shifts to page beyond the newest 20 records and Latest shifts to return.

Expected cash is opening float plus payments minus refunds and cash corrections. A positive report movement enters the drawer; a negative one leaves it. Difference is declared minus expected. Minor units and currency precision remain exact, including currencies without decimals. One drawer may be open per property. Negative expected cash is visible, never silently clamped. A refund or reversal belongs to the drawer open when it is recorded; an earlier closed report never changes. Idempotent retries keep their original attribution.

Administrators configure Require an open shift for cash postings and the nonnegative threshold. Enforcement is off by default: cash recorded without an open drawer then has a null shift reference and is absent from shift reports. With enforcement enabled, open a drawer before retrying cash_shift.required. Card-terminal, bank-transfer and other methods are outside the drawer. No online money transfer or fiscal document is produced.

All paths below are under /properties/{property_id} and respect workspace and property RLS. API keys and device tokens use the live member permissions as browser requests do.

Operation Permission Version
GET /cash_shift_context Any cash shift grant Currency/time zone only
GET /cash_shift_settings cash_shifts.read or cash_shifts.configure Returns settings ETag
PUT /cash_shift_settings cash_shifts.configure Settings If-Match
GET /cash_shifts/current cash_shifts.read Returns open shift ETag or null
GET /cash_shifts?limit=20&cursor=… cash_shifts.read Newest first, opaque cursor
POST /cash_shifts cash_shifts.open New drawer, no If-Match
GET /cash_shifts/{id} cash_shifts.read Report and shift ETag
POST /cash_shifts/{id}/close cash_shifts.close Shift If-Match

Settings input is { "require_open_shift": true, "discrepancy_threshold": "5.00" }. Opening input is { "opening_float": "100.00" }; closure is { "declared": "150.00", "reason": null }. Amounts are decimal strings in the property’s currency; response monetary objects carry amount and currency. Cash postings change the shift version, so clients read it immediately before closing. Open/close return the shift only to cash readers, otherwise CashShiftAcknowledgement. The server selects the nullable posting reference; it is never accepted as client input.

The SDK exposes cashShiftSettings.get/update and cashShifts.current/list/create/get/close, with generated React query factories. cashShifts.context returns only currency/time zone for module-only custom roles without requiring properties.read. Built-in admin/front desk/accounting may open and close; admin/front desk/accounting/revenue manager/viewer may read; only admin configures. Custom roles can grant these separately within the member’s own live permissions and property selection.

cash_shift.already_open recovers by using the current drawer; cash_shift.closed by opening a new one; cash_shift.version_mismatch by refreshing/recounting. cash_shift.reason_required requires an explanation. Field-linked cash_shift.invalid rejects invalid amounts; cash_shift.amount_exceeded rejects arithmetic outside the exact supported range. No write survives a denied permission, invalid input or failed transaction.

Cash history returns { data, next_cursor, has_more }; pass the returned cursor unchanged. Invalid cursors return cursor.invalid. Reports resolve opening/closing actor names live; unavailable members have a readable fallback.