Payments & Stripe
The Billing module supports both manual payment recording and automated payment processing through Stripe Connect. This page covers setting up Stripe, accepting payments, managing payment methods, processing refunds, and the autopay experience.
Payment Overview
Payments in concorbit are recorded against invoices. Each payment tracks:
| Field | Description |
|---|---|
| Amount | The payment amount in minor currency units (pence/cents). |
| Currency | The payment currency. |
| Method | How the payment was made (Stripe, bank transfer, cheque, cash, other). |
| Reference | Optional external reference (bank transfer ref, cheque number, etc.). |
| Stripe payment ID | The Stripe payment identifier (for Stripe payments). |
| Status | The payment status. |
| Notes | Optional notes about the payment. |
| Paid at | When the payment was received. |
A single invoice can have multiple payments (partial payments). The invoice is marked as Paid when the total of all payments meets or exceeds the invoice total.
The PaymentLedger as the source of truth
Every settlement (manual mark-paid, Stripe pay-now, autopay finalise, refund, credit-note application, QuickBooks payment sync) flows through PaymentLedgerService (app/Services/Billing/PaymentLedgerService.php). That makes the payments table the single ledger for invoice money movement; invoices.amount_paid is always a materialised sum of the ledger, never a shortcut value.
Concretely:
A positive settlement writes a payment row with
status='succeeded'(or'completed'from QuickBooks) and a positive amount.A refund writes a signed negative row with
status='refunded'. Refunds are recorded per-refund-id, not as a cumulative delta, so out-of-order webhook delivery is safe.A void writes nothing to the ledger; the existing row's
statusflips tovoidedand is excluded from the settled total.
The settled total counts succeeded, completed, and refunded rows (signed). voided, pending, and failed are excluded. Idempotency is two-layered:
existingByReferencefinds a prior row by(payment_source, external_reference)and returns it untouched.A DB partial unique index catches a race where two callers insert at once; the savepoint catches the 23505 and re-reads the winner.
Recording a payment against an AT-governed or QB-governed invoice is refused at the service. AT and QB own the paid state for their rows; a concorbit-side payment would immediately desync on the next sync pull.
Payment sources
payments.payment_source is the canonical vocabulary for who recorded the settlement:
| Source | Written by | Notes |
|---|---|---|
| stripe | StripeConnectService::finalizeInvoiceFromIntent and webhook handlers. | Portal pay-now, manual portal card, customer self-service. |
| autopay | AutopayService::charge. | Off-session card charges for recurring agreements and one-off card invoices. |
| manual | InvoiceController::recordPayment. | Bank transfer, cheque, cash, other. |
| quickbooks | QuickBooksInvoiceSync payment-pull. | Mirrors a QB-side payment row. Uses ledger upsert so QB-side edits propagate. |
| credit_note | CreditNoteService::apply. | Applies a credit note's amount against an invoice; recorded as a credit_note-sourced settlement. |
| stripe_dispute | Reserved for the dispute workflow. | Not currently written; charge.refunded remains the sole money-movement authority. |
The payment_source value is rendered as a chip on the staff invoice page and the portal invoice page so finance can see at a glance how an invoice was settled. The reconciliation view (/reconciliation) filters by source.
Stripe Connect Setup
Stripe Connect allows your workspace to accept online payments from contacts. concorbit uses Stripe Connect so that payments flow directly to your Stripe account.
Prerequisites
A Stripe account (create one at stripe.com if you do not have one).
Workspace admin permissions (
settings.tenant).
Connecting Stripe
Navigate to Settings > Payments.
Click Connect Stripe Account.
You are redirected to Stripe's authorisation page.
Log in to your Stripe account (or create one).
Authorise concorbit to connect to your account.
You are redirected back to concorbit. A confirmation message appears.
Once connected, your workspace can:
Accept online payments on invoices.
Store payment methods for contacts.
Process autopay charges for subscriptions.
Issue refunds.
Refreshing the Connection
If your Stripe connection needs to be refreshed (e.g. after Stripe account changes):
Navigate to Settings > Payments.
Click Refresh Stripe Connection.
Complete the Stripe authorisation flow.
Disconnecting Stripe
To remove the Stripe integration:
Navigate to Settings > Payments.
Click Disconnect Stripe.
Confirm the disconnection.
After disconnecting:
Online payment links on invoices will no longer work.
Autopay will stop for all subscriptions.
Existing payment records are retained.
You can reconnect at any time.
Accepting Payments
Online Payments via Portal
When Stripe is connected and a contact receives an invoice:
The contact receives an invoice email with a link to the client portal.
In the portal, the contact sees the invoice details and a Pay Now button.
Clicking Pay Now initiates a Stripe payment.
The contact enters their payment details (card number, etc.) in a secure Stripe-hosted payment form.
On successful payment, the invoice is automatically marked as Paid.
The payment is recorded against the invoice with the Stripe payment ID.
Stripe Checkout
For some payment flows, concorbit uses Stripe's embedded checkout experience. The contact completes payment without leaving concorbit, the Stripe PaymentElement is rendered directly in the portal.
Manual Payment Recording
For payments received outside Stripe:
Open the invoice.
Click Record Payment.
Enter:
Amount received.
Method (bank transfer, cheque, cash, other).
Reference (optional).
Notes (optional).
Date paid.
Click Save.
The payment is recorded and the invoice's outstanding balance is reduced. If the total paid meets or exceeds the invoice total, the invoice status changes to Paid.
Payment Methods Per Contact
concorbit stores payment methods (credit/debit cards) at the contact level through Stripe.
Adding a Payment Method
Navigate to the contact's record in the CRM.
Open the Payment Methods section.
Click Add Payment Method.
A Stripe setup form appears.
The contact (or you on their behalf) enters their card details.
The payment method is securely stored in Stripe and linked to the contact.
concorbit does not store raw card numbers. All card data is held securely by Stripe. concorbit only stores a reference to the Stripe payment method.
Setting a Default Payment Method
Each contact can have multiple payment methods on file. One is marked as the default:
Open the contact's payment methods.
Click Set as Default on the desired payment method.
The default payment method is used for autopay charges.
Removing a Payment Method
Open the contact's payment methods.
Click Remove on the payment method.
Confirm the removal.
The payment method is removed from Stripe. If it was the default, autopay will not work until a new default is set.
Autopay
Autopay automatically charges a contact's default payment method when a subscription invoice is generated.
Enabling Autopay
Autopay is toggled per contact, not per subscription:
Navigate to the contact's record.
Open the Payment Methods section.
Toggle Autopay on.
The contact must have at least one payment method on file with a default set.
How Autopay Works
A subscription's billing date arrives.
concorbit generates an invoice for the subscription.
Because the contact has autopay enabled, concorbit initiates a Stripe charge for the invoice total against the contact's default payment method.
If successful: The payment is recorded, the invoice is marked as Paid, and the contact receives an "Autopay successful" email notification.
If failed: The invoice remains unpaid, the payment failure is recorded on the subscription, and the contact receives an "Autopay failed" email notification with instructions to update their payment method.
Autopay Email Notifications
Two system email templates handle autopay notifications:
Autopay successful: Sent when a charge succeeds. Confirms the amount and invoice.
Autopay failed: Sent when a charge fails. Includes a link to the portal to update the payment method.
Both templates can be customised from the Email module's system templates section.
Portal Autopay Management
Contacts can manage their own autopay settings through the client portal:
View stored payment methods.
Add or remove payment methods.
Set a default payment method.
Enable or disable autopay.
This self-service capability reduces the administrative burden on your team.
Refunds
Stripe Refunds
For invoices paid through Stripe:
Open the paid invoice.
Click Refund.
Enter the refund amount (full or partial).
Confirm the refund.
concorbit initiates a refund through Stripe.
The invoice status changes to Refunded.
Stripe processes the refund to the original payment method. Refund processing time depends on the card issuer (typically 5-10 business days).
Manual Refunds
For payments received outside Stripe, refunds must be processed manually through your bank or payment processor. Record the refund in concorbit by:
Creating a Credit Note for the refund amount.
Noting the refund details in the credit note.
Payment History
Per-Invoice Payment History
Each invoice shows all payments recorded against it, including:
Payment amount and date.
Payment method.
Reference number.
Stripe payment ID (for online payments).
Per-Contact Payment History
View all payments made by a specific contact through their invoices. On the canvas, the Invoice List panel filters by contact when one is selected, showing all their invoices and payment statuses.
Webhook Configuration
Stripe communicates payment events (successful charges, failed charges, refunds) to concorbit via webhooks. These are configured automatically when you connect Stripe. If you need to troubleshoot payment notifications:
Check your Stripe dashboard for webhook delivery status.
Verify that the webhook endpoint is active and receiving events.
Review the payment and invoice records in concorbit to confirm events were processed.
Security
PCI compliance: concorbit never stores raw card numbers. All payment data is handled by Stripe's PCI-compliant infrastructure.
Stripe Connect: Payments flow directly to your Stripe account. concorbit acts as a platform facilitating the connection, not as an intermediary holding funds.
Encrypted data: Sensitive payment-related fields (like cancellation reasons) are encrypted at rest in concorbit's database.
Troubleshooting
Payment Not Appearing on Invoice
Check the Stripe dashboard for the payment status.
Verify that the webhook is active and events are being delivered.
Confirm that the payment was made against the correct invoice.
Autopay Not Charging
Verify that the contact has autopay enabled.
Confirm that a default payment method is set.
Check the Stripe dashboard for any issues with the payment method (expired card, insufficient funds).
Review the subscription's payment failure count and last failure date.
Stripe Connection Issues
Ensure your Stripe account is in good standing.
Try refreshing the Stripe connection from Settings > Payments.
If the connection is broken, disconnect and reconnect Stripe.