Skip to main content
ClientNest365ClientNest365

Invoicing and payment

How to send an invoice from a portal

Building an invoice in the workspace, sending it to a client, and tracking payment through to settled status. Covers the invoice builder, PDF output, and webhook events.

Audience: owner · 4 min read · Last reviewed

Invoices live at /app/invoices. Each invoice belongs to one client, has line items, and tracks status through the lifecycle (Draft → Sent → Viewed → Paid, with an Overdue state if past due).

Create an invoice

/app/invoices+ New invoice.

The builder:

  1. Pick a client. The dropdown lists every client with at least one slot consumed.
  2. Invoice number. Auto-incremented from your last invoice. Override if you maintain a custom numbering scheme (INV-2026-001, SA-PRACTICE/26/045, etc.).
  3. Issue date and due date. Issue defaults to today, due defaults to today + 14 days. Override per client (Italian SMEs often want 30 days; UK practices often default to 14).
  4. Line items. Each line has description, quantity, unit price. Add as many as needed.
  5. Tax/VAT rate. Per workspace default + per-line override. UK practices default to 20% VAT; agencies often run 0% on cross-border invoices.
  6. Notes. Free text shown on the invoice PDF and the client's invoice card. Useful for "Net 14, bank details on the PDF" or "Reverse charge applies, see VAT note."
  7. Save as Draft (no email goes out) or Send to client (email + portal card both fire).

What the client sees

The client gets an email pointing to the portal. The subject reads:

Invoice [number] from [your firm name]

The body shows the invoice total, due date, and a button to open the portal. In the portal, the invoice appears in /portal/c/<slug>/invoices with:

  • The PDF preview embedded
  • A status badge (Sent / Viewed / Paid)
  • A Pay invoice button if payment is configured

Payment

ClientNest365 supports a payment-provider abstraction layer. Production deployments wire in a provider (Lemon Squeezy, Paddle, Mollie, Adyen, etc.) via the PaymentProvider interface. The current default for local dev is MockProvider.

When the client clicks Pay invoice:

  1. The portal redirects to the provider's hosted checkout page.
  2. The client enters card details on the provider's domain (PCI scope stays with the provider, not with you).
  3. The provider charges the card and posts back a webhook to /api/payments/webhook with the result.
  4. The portal updates the invoice status to Paid.
  5. The client returns to the portal with a confirmation page.

Webhook events you can subscribe to (Settings → Webhooks):

  • invoice.sent (fired when you mark an invoice as Sent)
  • invoice.viewed (fired when the client opens the invoice in their portal)
  • invoice.paid (fired when the payment provider confirms payment)
  • invoice.overdue (fired daily at 9am if an invoice passes its due date unpaid)

Most owners wire invoice.paid to a Slack channel so the team gets an internal notification when money lands.

PDF generation

Invoice PDFs are generated server-side using react-pdf. The PDF includes:

  • Your firm's logo (uploaded in Settings → Branding)
  • Your firm's name, address, phone, registration number (from Settings → Firm details)
  • Client name and primary contact
  • Invoice number, issue date, due date
  • Line items with subtotal and tax breakdown
  • Bank details (if configured) for wire transfer
  • Notes from the invoice

PDFs are persistent: stored in R2 with a signed-URL generator. You can re-download an old invoice years later. Clients can re-download too, from their portal's Invoices section.

Editing a sent invoice

A sent invoice is immutable in the data layer (auditable record). To make corrections:

  1. If the invoice hasn't been paid: void the original (status: Voided), then issue a credit note (negative-value invoice with reference to the original number).
  2. If the invoice has been paid: same pattern. A credit note with reference, plus a refund through the payment provider if applicable.

The audit log captures every status change with timestamp and actor, so you can prove the trail if asked.

Templates and recurring invoices

If you bill the same line items repeatedly (monthly retainer, quarterly fee), set up an invoice template:

/app/invoices/templates+ New template

A template is an invoice scaffold without a specific client. To use:

  1. /app/invoices+ New invoice from template
  2. Pick the template
  3. Pick the client
  4. Pick the issue date

The line items and notes pre-populate; you edit any specifics for this period.

For true recurring invoicing (auto-generate on the 1st of each month), set the template to Recurring → Monthly. The cron loop creates a new draft invoice each cycle. You review and send manually (most owners want a human in the loop for invoice send).

Multi-currency

Invoices respect the workspace base currency (EUR, USD, or GBP), and clients can have a per-client default currency override.

The ECB rate is fetched at the moment the invoice is issued and locked into the invoice record. Subsequent rate changes don't affect already-issued invoices. This makes the invoice number both stable and audit-defensible.

What about VAT?

The invoice builder supports per-line VAT rates and reverse-charge labelling. For EU B2B clients in another member state, the typical pattern is:

  • VAT rate: 0%
  • Notes: "Reverse charge applies under Article 196 of Council Directive 2006/112/EC. Customer accounts for VAT."

Save these as a per-client invoice template so you don't re-type the legal text each time.

What this looks like in practice

The agency walkthrough and law firm walkthrough both show invoicing inside the end-to-end engagement flow, with screenshots of the agency and client sides.