Skip to content

6. Money and payments

Rule. Record the debt first, add a payment rail second. Money is always an integer in minor units with its currency. Stripe and Razorpay are both supported, alongside offline payments with receipts.

Why. A space can owe or be owed money with no payment provider. Floats lose cents. Currencies differ in decimals (JPY none, KWD three).

How to apply.

  • Ledger before gateway. Every charge is recorded whether or not an online provider is configured. The ledger is permanent core; only the online rail (checkout, refunds, provider settings, webhooks) is removable. A purge never deletes a payment.
  • Minor units and currency. Store integers (paise, cents) with an ISO currency code, or fixed-point decimals. Never float. Never add across currencies. Round with the currency’s own decimals.
  • Providers. Each space or organisation uses its own Stripe or Razorpay account; there is no platform fee or platform-wide fallback key. Support both in every product that takes money. Supporting offline too: cash, bank transfer, UPI, card terminal, pay later, recorded by staff.
  • Offline needs a receipt. Marking a charge paid offline writes a settlement record (method, reference, received date) once; corrections are new rows that amend, never edits. An optional maker-checker rule can require a second person to confirm.
  • Idempotent. The same webhook event or order key never settles twice (processed-event table, order idempotency key). Razorpay deliveries are de-duplicated by event id and by a hash of the signed body.
  • Webhooks are verified with the provider’s signature, per space, before any state changes; unknown tenants and archived spaces are refused.
  • Provider switch keeps old keys usable. After a space switches from one provider to the other, the old provider’s keys stay usable for settling and refunding existing charges. Rotating or clearing keys refuses while collections are pending.
  • Unknown outcome stays pending. A provider timeout or unreadable response leaves the charge pending and reserved; it is never guessed as paid or failed.
  • Refunds follow the space’s refund policy, are recorded as their own rows and never exceed what was paid.
  • Secrets never leave the server. Provider keys and webhook secrets are write-only in every screen, encrypted at rest with a key bound to the tenant, and never in logs, audit metadata, URLs or API replies. Only publishable keys go to the browser or the app.
  • Receipts are numbered without gaps; credit notes for refunds; tax receipts (for example GST) where a product needs them.
  • Prize money and payouts are recorded by a person, never sent automatically.

Across the org.

Product Money today
SpaceWorks Stripe and Razorpay per space, offline with receipts, charge tracking independent of the payments rail, reconciliation, refunds
Events Razorpay and Stripe on the organiser’s account, pay at the desk, refunds, PDF receipts, chargeback alerts
Machines Razorpay or Stripe, or desk payments (cash, UPI, bank, card terminal), optional maker-checker
Inventory Razorpay, Stripe, cash or bank, or pay later, for late fees and damage charges
Bookings Razorpay Checkout, Stripe Checkout, cash, UPI, bank, pay later, gapless receipts and credit notes
Organization Razorpay, Stripe, UPI, bank, cash, GST receipts
Workspace Finance records (income, expenses, bills, reimbursements, payroll records); no payment gateway found
iOS / Android Server-selected checkout (iOS: Stripe SDK and Razorpay per README); Android: Stripe Android SDK per the SpaceWorks mobile spec, Razorpay not checked

Part of Space Works product rules, published from docs/product-rules.md. Edit it there.