Payments

Current invoice-payment capabilities, limitations, and safe collection alternatives.

Leenops records invoice payments and supports bank reconciliation. At the currently audited application release (e31409a7), Stripe Checkout service code also exists, but the customer-facing online-payment journey is not ready for live use.

Do not enable or advertise emailed online invoice payment for customers yet. The email's Pay online hyperlink targets an endpoint that accepts only POST requests. Email clients open links with GET, so the current CTA returns 405 instead of opening Stripe Checkout.

Current capability matrix

CapabilityCurrent state
Manual and bank payment recordsAvailable
Bank transaction reconciliationAvailable
Stripe hosted Checkout creationAvailable only through a workspace-user action that performs POST
Shareable Checkout URL from invoice detailCan be generated manually; treat as test-only until hardening is complete
Emailed Pay online CTABroken: GET points to a POST-only route
Customer invoice portal/pay pageNot implemented
MollieNot available in the audited release; a later local implementation is under development but is not yet a shipped capability
PayPal, Adyen, Bancontact, iDEAL, SEPA provider flowsNot implemented
Card-on-file recurring paymentsNot implemented
Refund UINot implemented

What works for workspace users

For a sent or overdue invoice, an authenticated workspace user can choose Pay link on the invoice detail. Leenops performs a POST request, asks the active Stripe configuration to create a hosted Checkout session, and returns the Stripe URL.

This proves the Stripe integration has a functioning checkout-creation path. It does not make the normal email journey complete or approve the flow for production use.

The current sequence is:

Send invoice
  → email renders /api/finance/invoices/{id}/pay as an anchor
  → customer clicks the anchor
  → email client performs GET
  → route exports POST only
  → 405 Method Not Allowed

The production design needs a tokenized customer-facing GET page or portal. It must not use a raw invoice identifier as the sole customer capability.

Settlement status

Stripe webhook code can verify a provider signature, persist a payment record, and recompute an invoice's paid amount/status. Before live enablement, the complete flow still needs enforced workspace ownership, invoice eligibility, expected amount/currency checks, safe return URLs, retry/idempotency tests, and a customer-safe capability model.

Succeeded, failed, and refund-related provider states in the data model do not imply that every related UI journey is implemented.

Safe collection workflow today

  1. Send the invoice PDF without relying on the online-payment CTA.
  2. Include the workspace IBAN and payment reference.
  3. Import or synchronize bank transactions.
  4. Match the transaction to the invoice in Banking.
  5. Verify the invoice balance and status after reconciliation.

Readiness checklist

Online invoice payment can be documented as ready only after all of these are true in a committed and deployed release:

  • a customer-safe GET page uses an expiring, revocable token;
  • draft, void, fully paid, or cross-workspace invoices cannot create checkout;
  • return URLs come from trusted configuration rather than request headers;
  • amount, currency, workspace, invoice, and provider metadata are verified during settlement;
  • provider credentials are server-only and cannot be selected into browser data;
  • duplicate and out-of-order webhook tests pass;
  • the emailed CTA passes an end-to-end browser test;
  • refund and failure recovery behavior is documented from working code.