Quotation¶
Read cost breakdowns, override pricing per-project, set machine hour rates, and walk away with a styled CSV or Excel quote.
Concepts¶
| Term | What it is |
|---|---|
| Quote job | Per-project quotation state (1:1 with projects, auto-created). Holds the overrides that diverge from machine defaults: MHR override, setup-cost overrides, additional costs, pricing parameters, material price/surcharge. |
| Cost breakdown | The on-the-fly calculation that combines machining time (from the CAM job), MHR, setup costs, material cost, additional costs, overhead, profit, discount, and tax. Read-only; never persisted. |
| Machine MHR | The Machine Hour Rate stored on each machine product (product_id). Defaults flow through to quote jobs unless overridden per-project. The MHR can be set directly or computed from a costing model. |
| Setup cost | Two layers: machine defaults (per product_id, reused across projects) and per-project overrides keyed by CAM setup entity UUID. |
| Additional cost | Per-project line items grouped by name (e.g. "Surface treatment" → list of entries). No machine defaults. |
| Quote settings | Per-user defaults applied when a new quote job is created (overhead, tax, discount, profit, default cost-per-m², default energy cost). |
Endpoints¶
Per-project quote¶
| Method | Path | Scope |
|---|---|---|
GET |
/projects/{project_id}/quote |
quote:read |
GET |
/projects/{project_id}/quote/job |
quote:read |
PATCH |
/projects/{project_id}/quote/job |
quote:write |
POST |
/projects/{project_id}/quote/export |
quote:export |
Per-machine quote configuration¶
| Method | Path | Scope |
|---|---|---|
GET |
/libraries/machines/{product_id}/quote |
quote:read |
PATCH |
/libraries/machines/{product_id}/quote |
quote:write |
POST |
/libraries/machines/{product_id}/quote/setup-costs |
quote:write |
DELETE |
/libraries/machines/{product_id}/quote/setup-costs/{cost_index} |
quote:write |
MHR (Machine Hour Rate)¶
| Method | Path | Scope |
|---|---|---|
POST |
/quote/mhr/calculate |
quote:read |
GET |
/libraries/machines/{product_id}/mhr |
quote:read |
POST |
/libraries/machines/{product_id}/mhr |
quote:write |
DELETE |
/libraries/machines/{product_id}/mhr |
quote:write |
Per-user defaults¶
| Method | Path | Scope |
|---|---|---|
GET |
/quote/settings |
quote:read |
PATCH |
/quote/settings |
quote:write |
The full request/response schemas live in the Scalar reference.
Layered defaults¶
The breakdown calculator stacks values from three layers, deepest first:
- Quote settings (per user): supply the overhead/tax/discount/profit a new quote job is born with.
- Machine (per
product_id): provides the MHR and the setup-cost template for any project that uses that machine. - Quote job (per project): overrides any of the above. A null override means "fall through to the machine, then settings".
Setup-cost merging is keyed by CAM setup entity UUID: the breakdown lists one entry per machining setup, takes the user override if present, otherwise the machine default. Add or remove machine defaults to change the template; add a per-project override only when one project diverges.
material_is_fixed_price=true short-circuits material pricing: the quote uses material_fixed_price directly, ignoring stock weight × library price × surcharge.
Flow: read the breakdown¶
import requests
API = "https://app.autonomiq.de/backend-api/api/public/v1"
H = {"X-API-Key": "smk_live_..."}
# Fast path: just the numbers
breakdown = requests.get(f"{API}/projects/{PID}/quote", headers=H).json()
print(breakdown["total_price"], breakdown["manufacturing_cost"])
# Full state: every override, cost, parameter currently on the job
job = requests.get(f"{API}/projects/{PID}/quote/job", headers=H).json()
Flow: override pricing on one project¶
# Bump quantity to 25, override the MHR for this run, add a one-off cost
requests.patch(
f"{API}/projects/{PID}/quote/job",
json={
"quantity": 25,
"mhr_override": 95.0,
# additional_costs: keyed by group ID (arbitrary string), values have
# "Title" (display name), "per_unit" (bool), and "Costs" list where each
# item uses "label" and "cost" (float).
"additional_costs": {
"shipping": {
"Title": "Shipping",
"per_unit": False,
"Costs": [{"label": "DHL Express", "cost": 28.0}],
},
},
"overhead_percentage": 12.0,
"tax": 19.0,
"discount": 5.0,
"profit": 10.0,
},
headers=H,
).raise_for_status()
# Override one specific CAM setup's clamping cost (others fall through to machine default).
# First discover the setup entity UUIDs from the quote job:
job = requests.get(f"{API}/projects/{PID}/quote/job", headers=H).json()
setup_uuid = next(iter(job["setup_costs"])) # take the first setup
# Each entry has: is_fixed_price ("true"/"false"), name, value, unit, fix_price (all strings).
# is_fixed_price="true" → uses fix_price in the breakdown (one-time fixed amount)
# is_fixed_price="false" → uses value in the breakdown (hourly-rate style)
requests.patch(
f"{API}/projects/{PID}/quote/job",
json={
"setup_costs": {
setup_uuid: {
"is_fixed_price": "true",
"name": "Custom fixture",
"value": "0",
"unit": "EUR",
"fix_price": "35.0",
},
},
},
headers=H,
).raise_for_status()
PATCH is partial: only fields you send are touched. Pass mhr_override: null to clear an override and fall back to the machine default.
Flow: configure a machine's MHR and setup costs¶
# Direct MHR set (skips the costing formula)
requests.patch(
f"{API}/libraries/machines/{product_id}/quote",
json={"mhr_value": 88.0, "name": "DMU 50 (rev B)"},
headers=H,
).raise_for_status()
# Add a default setup cost that flows into every project on this machine
requests.post(
f"{API}/libraries/machines/{product_id}/quote/setup-costs",
json={"name": "Tool change", "value": 5.0, "unit": "EUR"},
headers=H,
).raise_for_status()
# Remove a specific entry by index (zero-based, returned by GET)
requests.delete(
f"{API}/libraries/machines/{product_id}/quote/setup-costs/2",
headers=H,
).raise_for_status()
Flow: calculate MHR from cost inputs¶
POST /quote/mhr/calculate is preview-only: it returns the MHR but persists nothing. Useful for "what-if" sliders before committing.
mhr_inputs = {
"acquisition_costs": 250000.0,
"machine_selling_price": 25000.0,
"interest_rate": 0.05,
"required_floor_space": 20.0,
"cost_per_square_meter": 10.0,
"maintenance_cost": 5000.0,
"energy_cost": 0.20,
"average_power_consumption": 15.0,
"operating_hours": 1800.0,
"years": 10.0,
"safety_factor": 5.0,
}
preview = requests.post(
f"{API}/quote/mhr/calculate",
json=mhr_inputs,
headers=H,
).json()
print(preview["calculated_mhr"]) # e.g. 85.42
# Commit to a specific machine (same inputs as the preview)
requests.post(
f"{API}/libraries/machines/{product_id}/mhr",
json=mhr_inputs,
headers=H,
).raise_for_status()
# Read it back later
mhr = requests.get(
f"{API}/libraries/machines/{product_id}/mhr",
headers=H,
).json()
POST /libraries/machines/{product_id}/mhr overwrites both calculated_mhr AND the input parameters used to derive it; subsequent GET returns both, so the formula stays auditable.
Flow: download the styled quote¶
# CSV (English)
csv = requests.post(
f"{API}/projects/{PID}/quote/export",
params={"format": "csv", "language": "en"},
headers=H,
).content
open("quote.csv", "wb").write(csv)
# Excel (German)
xlsx = requests.post(
f"{API}/projects/{PID}/quote/export",
params={"format": "excel", "language": "de"},
headers=H,
).content