Billing
Fixed-price vs time-and-materials billing, billing status tracking, and how amounts flow from FiC.
Billing
Billing types
Fixed price (fixed)
The client pays an agreed amount regardless of hours used. This is the default.
- Budget health compares burn % vs completion % — burning fast with low completion triggers alerts.
quotedAmountNetis locked at project creation.- Overspend directly erodes margin.
Time and materials (time_and_materials)
The client is invoiced for actual hours logged at an agreed rate.
- Budget health is not alarmed on
fixed-style overruns — the model is different. trackedCost(sum ofmember.pricePerHour × logged hours) is the billable amount.invoicedAmountNettracks what has actually been invoiced.
Billing status
| Status | Meaning |
|---|---|
executing | Work in progress |
to_invoice | Work complete, invoice not yet issued |
invoiced | Invoice issued in FiC |
Transition executing → to_invoice happens when you mark a project as completed. Update to invoiced manually once the invoice is created in FiC.
FiC amounts
When a project is created from a FiC quote, PayMe captures:
quotedAmountNet— net amount from the quote line itemsourceQuoteId,sourceQuoteItemId— links back to FiC for cross-referenceficEntityId— the FiC client entity
invoicedAmountNet is updated when you manually record invoiced amounts, or via FiC invoice sync.
Quote drafts
Creating a draft saves a quote in FiC. Email delivery is a separate action.
Review the client, period, quantities and net unit prices before creating the draft. The company default_hourly_rate and member pricePerHour inform the wizard pricing preview. Changing the billing period updates the preview. The draft endpoint uses the approved line items exactly as submitted.
A linked FiC client is required. PayMe reads that client's billing details from FiC. Tax uses the client's configured default VAT, or the company's quote item default when the client has none. Missing tax configuration stops creation.
Draft API
POST /api/pm/quotes/draft requires a PM or admin session.
type QuoteDraftRequest = {
description: string;
ficEntityId: number;
clientName?: string;
items: {
name: string;
quantity: number;
netPrice: number;
description?: string;
periodLabel?: string;
}[];
notes?: string;
periodLabel?: string;
projectId?: string;
};
type QuoteDraftResult = {
ok: true;
quoteId: number;
source: "fic";
totalNet: number;
warning?: string;
};ficEntityIdis a positive integer. FiC's current client name is authoritative;clientNameis optional preview context.descriptionbecomes both the internal and visible quote subject. It accepts 1 to 2,000 characters after trimming.itemsaccepts 1 to 200 lines. Names accept 1 to 500 characters, quantities must be positive finite numbers, and net unit prices must be finite and nonnegative.- Optional line descriptions accept up to 2,000 characters. Period labels accept 1 to 200 characters and are appended to the corresponding line description or document notes. Notes accept up to 10,000 characters.
projectId, when provided, must be a UUID. Unknown fields are rejected.totalNetis the sum ofquantity × netPrice, before tax. All prices are net EUR; FiC receivescurrency: { id: "EUR" }anduse_gross_prices: false.
Success returns HTTP 200 with a positive quoteId. Invalid input returns HTTP 400. Configuration and FiC errors use the standard { error, status, code?, detail? } response; there is no local-storage substitute. The FiC connection needs entity.clients:r for client lookup and issued_documents.quotes:a for creation.
If project document linkage fails after FiC has created the quote, the response still contains its ID and a warning. The server logs fic_quote_project_link_failed with the exact project/document identity and repair operation. Repair that link without creating another quote. If FiC returns no valid ID, creation reports failure; inspect FiC before retrying because the document may already exist.
Net cost
netCost = sum(member.pricePerHour × logged hours across all members)
This is the internal cost of the project. Compare against quotedAmountNet to see margin. Available in the Client Profitability report.