Money

Payments

The provider-agnostic, webhook-confirmed engine behind online invoice payment.

Updated 2026-06-2310 sections5 min readFor the marketing team

1In one sentence#

The Payments module is the money-collection engine behind LumosCRM — a provider-agnostic system that takes card payments on invoices (today via Stripe), treats the provider's webhook as the single source of truth, records every payment and refund as an internal, auditable transaction, and keeps the rest of the CRM cleanly decoupled from any one payment provider.

It's mostly invisible to everyday users — they experience it as the "Pay online" button on an invoice — but it's the part that makes sure money actually moves, is reconciled correctly, and is never double-counted.

2Who it's for#

RoleWhat they get
Clients (external)A simple, secure card-payment experience from an invoice's public link.
FinanceReliable payment records, partial/refund tracking, and a clean reconciliation trail.
Engineering / opsA provider-agnostic design — add or swap providers without touching the rest of the CRM.
LeadershipConfidence that "paid" means the money truly arrived.

3The core idea: provider-agnostic, webhook-confirmed#

LumosCRM keeps its own internal record of every payment, independent of the provider:

   Client clicks "Pay" ──▶  Provider (Stripe) hosted checkout
                                      │
                       (card processed by provider)
                                      │
                        Provider WEBHOOK  ◀── the source of truth
                                      │
                 ┌────────────────────┴───────────────────┐
                 │  Payment record updated → status: paid   │
                 │  PaymentEvent logged (provider callback)  │
                 │  Invoice notified (event-driven) → paid   │
                 └──────────────────────────────────────────┘

The browser redirect after checkout is treated as a hint only — a payment is marked paid when the signed webhook confirms it, not when the customer's browser comes back. This prevents the classic failure modes (closed tab, flaky network) from ever marking an invoice paid prematurely or missing a real payment.

4Capabilities at a glance#

CapabilityWhat it means
Online card paymentsClients pay invoices by card through the provider's secure checkout.
Provider-agnosticA clean gateway abstraction; Stripe today, others additively, with a no-op fallback when none is configured.
Webhook-as-truthSettlement is confirmed by the provider's signed webhook, verified server-side.
Internal payment ledgerEvery payment is an internal, provider-independent record.
RefundsFull and partial refunds, tracked against the original payment.
IdempotencyBuilt-in safeguards so a payment is never recorded twice.
Polymorphic payablePayments attach to any payable record (invoices today), keeping the design open.
Event logEvery provider callback is recorded as a payment event for traceability.
Event-driven invoice updatesThe invoice is updated by listening for payment events — no tight coupling.

5How a payment is modeled#

Each payment is an internal record with:

  • What it's for — a polymorphic link to the payable (an invoice).
  • Type — currently one-off (recurring/subscription is a designed seam, see below).
  • Status — pending · processing · paid · partially refunded · refunded · failed · cancelled · expired.
  • Amounts — captured and refunded amounts in minor units (cents), plus currency, so figures are always exact.
  • Provider pointers — the provider name and its reference, treated as pointers only, never the source of truth.
  • Idempotency key — to guarantee a single payment is recorded once, even if a callback arrives twice.

Around it sit refunds (each refund tracked against its payment) and payment events (a log of every provider callback).

6The client payment experience#

From an invoice's public link (see the Invoice module), the client clicks Pay, is taken to the provider's secure hosted checkout, and pays by card. They never need a login, and no card data touches LumosCRM. On return they see a success or cancelled notice — but the invoice only flips to paid once the webhook confirms the money has settled.

Staff can also record payments manually (e.g. a bank transfer) and issue refunds from the invoice itself; both update the same internal ledger.

7Security & reliability#

  • Signed, verified webhooks: the webhook endpoint is unauthenticated by necessity (the provider calls it) but CSRF-exempt and signature-verified inside the controller, keyed by provider so adding providers is additive.
  • Idempotency at two layers: duplicate callbacks and double submissions can't create duplicate payments.
  • Truth lives with settlement: internal status follows the webhook, not the browser.
  • Decoupled by events: the Invoice module reacts to payment events rather than calling the provider directly, so billing and payments stay independent.

8Use cases & scenarios#

Use case A — Getting paid online#

A client opens their invoice link, pays €12,000 by card, and closes the tab before the redirect. The webhook still arrives, the payment is recorded, and the invoice flips to paid — nothing is lost.

Use case B — A partial refund#

A client is refunded €2,000 of a €12,000 payment. Finance issues the refund; the payment moves to partially refunded, the refunded amount is tracked, and the remaining balance is clear.

Use case C — No double-charging#

A provider sends the same webhook twice (it happens). The idempotency safeguard recognises it and records the payment only once.

9Platform foundations (built into the data model)#

  • Recurring / subscription billing is a deliberate seam — the payment type enum and design leave room for it, ready to activate when (e.g.) Stripe Billing is introduced. It is not live today.
  • Additional providers can be added without changing how the rest of the CRM works, thanks to the gateway abstraction and provider-keyed webhook endpoint.

For marketing: describe Payments as "secure online card payments on invoices, with reliable reconciliation." Avoid promising recurring billing or specific non-Stripe providers until they're enabled.

10Glossary#

TermMeaning
ProviderThe payment processor (Stripe today).
WebhookThe provider's signed server-to-server callback that confirms settlement — the source of truth.
PayableThe record a payment is collected against (an invoice).
IdempotencyThe guarantee a payment is recorded once, even on duplicate callbacks.
RefundA full or partial return of a payment, tracked against the original.
Minor unitsMoney stored in cents for exactness.

This document describes the Payments module as currently built: provider-agnostic online card payments on invoices via Stripe, webhook-confirmed. Recurring billing and non-Stripe providers are design seams, not live features.