Get Sales Order Financials (Proforma)
GET/api/sales-orders/:salesOrder/financials
Recalculates and returns proforma (on-the-fly) line-level financials for a single sales order. The endpoint runs the API::calculate for the order before responding, so figures always reflect current FIFO cost assignments — including the bundle cost-based revenue correction.
orders:readGrant this scope to your token under Settings → Developer → Personal Access Tokens.
Authentication: Requires Bearer token.
Response (wrapped in {data}):
- id: Sales order ID
- is_tax_included, currency (code cached at time of sale), currency_rate
- sales_order_lines[]: per-line proforma P&L:
- product: {id, sku, name} (present when the line is a product line)
- description, quantity, price (per-unit amount in tenant currency), tax_allocation, tax_rate_id
- revenue: recognized revenue for the line (after any bundle cost-based correction)
- revenue_allocation_basis: "document" (revenue follows the order document) or "cost_corrected" (bundle-group revenue re-allocated in proportion to actual COGS so no component shows a phantom line-level loss)
- document_revenue: pre-correction revenue computed from the order document (quantity × amount − included tax); equals revenue unless revenue_allocation_basis is cost_corrected
- bundle_id: parent bundle product ID when the line was expanded from a bundle (null otherwise)
- bundle_proration_basis: how the bundle's price was prorated across components at order entry — "cost", "price", or "quantity" (null for non-bundle or legacy lines)
- bundle: {id, sku, name} (present when bundle_id is set)
- revenue_allocated, credits, discount, total_revenue
- cogs, cost_allocated, cogs_returned, total_cost
- profit, profit_margin
- per_unit: {revenue, revenue_allocated, credits, discount, total_revenue, cogs, cost_allocated, cogs_returned, total_cost, profit}
- cost_breakdown: cost category → amount map
- cost_breakdown_layers[]: FIFO layer-level cost detail (layer_kind, fifo_layer_id, fifo_layer_date, quantity, source_type, source_label, source_id, breakdown, total, unit_cost)
- fifo_layers[]: {id, name, quantity, unit_cost, total_cost, layer_date}
Returns-pending COGS: each line splits returned cost into cogs_returned_realized (cost reversed by physical return receipts) and cogs_returned_pending (imputed expected cost of refunded units still awaiting return), with a return_pending boolean; the same split is available under per_unit.*. The order-level has_return_pending flag is true when any line has a return still in flight. A refunded-but-un-received order nets to ~0 while return_pending is true; closing or canceling the RMA without receiving the goods clears the pending imputation and reveals the real loss.
Each line includes indirect_cost_allocated (the line's revenue-weighted share of cost-entry / overhead allocations), contribution_profit (profit minus that share) and contribution_margin (a fraction of revenue), plus their per_unit variants. These are standalone — profit, total_cost and profit_margin are unchanged by them.
Request
Responses
- 200
- 401
- 403
- 404
- 429
OK
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Not found — no record with the given identifier (or the route does not exist). Verify the ID before retrying.
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.