Skip to content

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:

  1. Quote settings (per user): supply the overhead/tax/discount/profit a new quote job is born with.
  2. Machine (per product_id): provides the MHR and the setup-cost template for any project that uses that machine.
  3. 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