Invoicing
Every milestone in an active project generates an invoice. The invoice workflow tracks the lifecycle of each payment from draft through approval to settlement, with structured paths for disputes and rejections.
Flow
Invoice Creation
An invoice is created automatically when a milestone is marked complete. It inherits its financial values from the parent quote:
| Field | Calculation | Description |
|---|---|---|
amount | quote.amount × (milestone.percentage / 100) | Expert’s share for this milestone |
serviceFee | quote.serviceFee × (milestone.percentage / 100) | Platform fee for this milestone |
total | amount + serviceFee | Total amount associated with this invoice |
One invoice is created per milestone — enforced by a unique index on milestone. This means each milestone can only ever have one invoice, preventing duplicate billing.
Invoice Status Workflow
| Status | Transition Type | Meaning |
|---|---|---|
invoice_draft | — | Invoice created on milestone completion; awaiting approval |
invoice_submitted | positive | Raised by the expert, awaiting manager review |
invoice_approved | positive | Manager has approved |
invoice_sent | positive | Sent to the customer; awaiting payment |
invoice_disputed | negative | Manager has flagged an issue; loops back to submitted or draft after resolution |
invoice_paid | positive | Payment confirmed; project value released |
invoice_rejected | negative | Invoice rejected outright; terminal state |
Payment Recording
When an invoice is marked as paid:
paid = trueis set on the invoice recordpaidAtis required and must be provided — the model validates thatpaidAtexists wheneverpaidistrueisApproved = trueis set to indicate the full approval and payment cycle is complete
These flags are also surfaced as computed virtuals on the parent milestone (isPaid, isApproved), allowing milestone progress to be derived without joining the invoice collection.
Invoice Fields
| Field | Type | Description |
|---|---|---|
quote | Quote ref | The quote this invoice is billed against |
milestone | Milestone ref | The completed milestone this invoice covers (unique) |
lead | Lead ref | The originating lead |
expert | User ref | The expert being paid |
customer | User ref | The customer being billed |
manager | User ref | The CSM managing the invoice |
vendor | User ref | The vendor account |
amount | Number | Expert payment for this milestone |
serviceFee | Number | Platform fee for this milestone |
total | Number | Total amount |
status | String | Current invoice status name |
paid | Boolean | Whether payment has been received |
paidAt | Date | Required when paid = true |
dueDate | Date | Optional payment due date; falls back to the linked milestone’s due date when unset |
pdf | String | Invoice document URL |
Notifications
Key invoice events trigger platform notifications to the relevant parties:
| Event | Notification Key | Recipients |
|---|---|---|
| Invoice raised | invoice-raised | Manager, Customer |
| Invoice approved | invoice-approved | Expert |
| Invoice disputed | invoice-disputed | Expert |
| Invoice rejected | invoice-rejected | Expert |
| Payment confirmed | invoice-paid | Expert, Customer |