Functions reference

Every HTTP endpoint the app exposes — 193 endpoints across 35 routers — grouped by domain. For request/response schemas and a live "try it" console, use the auto-generated interactive docs at /docs (Swagger) / /openapi.json.

Conventions - Most endpoints require a session cookie and are scoped to the active workspace (tenant_id); sign in via POST /auth/login. - Magic-link / token endpoints (/portal/{token}, /supplier/respond/{token}, /q/{token}, /invites/{token}) are intentionally unauthenticated — the token is the credential. - /webhooks/* are verified by provider signature/handshake, not a session. - Each page in Screens lists the endpoints it calls.


Auth & access (26)

Authentication — auth_routes (/auth)

Method Path What
POST /auth/register Create a user + first workspace
POST /auth/login Password sign-in (may return a 2FA challenge)
POST /auth/logout End the session
GET /auth/me Current user + active workspace
POST /auth/switch-tenant Switch active workspace
POST /auth/forgot Request a reset link (always 200 — no account enumeration)
POST /auth/reset Set a new password from the emailed token
POST /auth/send-verification Send an email-verification link
POST /auth/verify-email Confirm an email address
POST /auth/mfa/enroll · /confirm · /disable Enrol / confirm / turn off TOTP 2FA
POST /auth/mfa/verify Login step two: exchange a password-stage challenge + TOTP/recovery code for a session

SSO — oidc (/auth/oidc)

Method Path What
GET / PUT /auth/oidc/{tenant_id}/config Read / set a workspace's OIDC config
GET /auth/oidc/{tenant_id}/login · /callback Start / complete an OIDC sign-in

Members & invites — members (/members), invites (/invites)

Method Path What
GET /members List workspace members + roles
POST /members Add an existing user to the workspace
GET / POST /members/invites List / create email invitations
POST /members/invites/{iid}/revoke Revoke a pending invite
PATCH / DELETE /members/{mid} Change a member's role / remove them
GET /invites/{token} Preview an invitation (unauthenticated)
POST /invites/{token}/accept Accept an invitation

Sales — quotes & BOQ (28)

Quotes, lines & BOQ — quote_lines

Method Path What
GET /quotes All quotes, newest first (Quotes page)
GET /quotes/{id} Quote header + lines (send/accept view)
GET /quotes/{id}/boq Rolled-up Section→Group→Line BOQ with sub-totals
GET /quotes/{id}/boq.pdf Server-rendered branded BOQ PDF (weasyprint)
POST /quotes/import-boq Ingest a reference-BOQ fixture → grouped draft quote
POST /quotes/extract-boq Raw rows / CSV → classify → grouped draft quote
POST /quotes/extract-boq-pdf Drop a BOQ PDF → Gemini transcribe → classify → quote
GET / POST /quotes/{id}/lines List / add lines
PATCH / DELETE /quotes/{id}/lines/{line} Edit / remove a line (while draft)
PATCH /quotes/{id}/lines/{line}/classify Human-verify a line's trade (learned per workspace)
POST /quotes/{id}/lines/reorder Reorder lines
POST /quotes/{id}/lines/{line}/choose Pick one option within a tier/alternative group
POST /quotes/{id}/recommend-lines Match a raw materials list → SKUs + suggested costs

Quote lifecycle — erp_routes, quotes

Method Path What
POST /quotes Create a quote
POST /quotes/{id}/send Send to client (freezes the lines)
POST /quotes/{id}/accept Mark accepted → creates a SOW
POST /plans/{plan_id}/quote Build a quote from a solved plan's BOM
GET /plans/{plan_id}/quote.pdf Quote PDF for a plan
POST /quotes/{id}/send-for-signing Push the quote PDF to PandaDoc as a draft, then send

Templates & share links — quote_templates, quote_share

Method Path What
GET / POST /quote-templates List / create reusable line bundles
GET / DELETE /quote-templates/{id} Get / delete a template
POST /quotes/{id}/apply-template Apply a template to a quote
POST /plans/{plan_id}/share Issue a public quote share link
GET /q/{token} View a shared quote (unauthenticated)

Sales — SOW, billing & variations (13)

SOWs — erp_routes

Method Path What
GET /sows All SOWs (SOW & milestones page)
GET /sows/{id} SOW header + milestones + scheduled invoices + variations
POST /sows/{id}/generate-pos Draft POs for the job, grouped by vendor
POST /billing/schedule-milestones Build the milestone schedule

Billing & payments — billing

Method Path What
POST /sows/{id}/invoices/schedule Draft client invoices from the milestone schedule
POST /invoices/{id}/push Push an invoice to the accounting provider (Xero/ERPNext)
POST /invoices/{id}/mark-sent Mark an invoice sent
POST /invoices/{id}/payments Record a client payment
POST /sows/{id}/retention/release Release a retention amount
POST /xero/reconcile-payments Pull recent Xero payments, mirror unseen ones locally

Variations — variation

Method Path What
POST /sows/{id}/variations Raise a variation order
POST /variations/{id}/approve Approve a variation
POST /variations/{id}/invoice Invoice an approved variation

Design pipeline — plans & geometry (38)

The sketch/scan → plan → BOM pipeline (absorbs the sketch2plan prototype).

Projects & ingest — projects (/projects), ingest

Method Path What
GET / POST /projects List / create projects
GET /projects/{id} Project detail (contract value, costs)
POST /projects/{id}/plans Create a plan under a project
POST /projects/{id}/ingest/dxf · /pdf · /photo · /disto Ingest a CAD/photo/measurement source → a plan

Plans, walls, openings, rooms, surfaces, fixtures — plans (/plans), walls, openings, rooms, surfaces, fixtures

Method Path What
GET /plans/{id} Plan state
POST /plans/{id}/solve Run the chain-solver geometry
POST /plans/{id}/confirm-dimensions Accept user-edited OCR dimensions, re-solve
POST /plans/{id}/detect-walls · /confirm-walls VLM interior-wall detection / persist edits
POST /plans/{id}/detect-doors · /confirm-doors Door detection / persist as openings
POST /plans/{id}/detect-fixtures · /confirm-fixtures Fixture detection / persist edits
POST /plans/{id}/extract-specs · /apply-specs Finishes-schedule VLM extract / apply SKU choices
POST /plans/{id}/disto Ingest Leica Disto measurements (CSV/JSON)
GET / POST /plans/{id}/scene Get / store the Floorplanner scene JSON
GET / POST /plans/{id}/walls, PATCH/DELETE /walls/{id} List / create / edit / delete walls
GET / POST /plans/{id}/openings, PATCH /openings/{id} Manage door/window openings
POST / GET /plans/{id}/detect-rooms · /rooms Detect / list rooms
POST /plans/{id}/decompose-surfaces · /decompose-by-room Build floor/ceiling/wall/skirting surfaces
GET / PATCH /plans/{id}/surfaces, /surfaces/{id} List / tag surfaces
GET / POST /plans/{id}/fixtures, PATCH /fixtures/{id} Manage fixtures

Catalog & pricing (14)

Catalog — catalog (/catalog)

Method Path What
GET / POST /catalog/categories List / create material categories
GET / POST /catalog/vendors List / create vendors
GET /catalog/skus List SKUs (optionally by category kind)
GET /catalog/skus/search Bilingual (中文 ⇄ EN) type-ahead over name/code/aliases
GET /catalog/skus/{id}/cost-suggestion Recommended cost from price history (median + p25/p75 + latest)
POST / PATCH /catalog/skus · /catalog/skus/{id} Create / edit a SKU (cost, aliases, reorder thresholds, material type)

Pricing intelligence — pricing (/pricing)

Method Path What
GET /pricing/sku/{id}/suggest Cost suggestion for a SKU
GET /pricing/sku/{id}/compare Compare a SKU's prices across observations/vendors
GET /pricing/vendor/{id}/scorecard Vendor price/lead-time scorecard
GET /pricing/projects/{id}/actuals A project's actual costs (committed POs / bills)
POST /pricing/anomaly-check Flag prices that look out of band

Procurement & RFQ (19)

Purchase orders, GRN & bills — procurement

Method Path What
GET /pos All purchase orders (procurement page)
GET /pos/{id} PO header + lines + goods receipts + vendor bills
POST /pos/{id}/send Issue a draft PO to the vendor
POST /pos/{id}/grn Record a goods receipt
POST /pos/{id}/bills Capture a vendor bill
POST /bills/{id}/match Run the 3-way match (PO ↔ GRN ↔ bill)
POST /bills/{id}/payments Record a vendor payment

RFQ & supplier portal — rfq

Method Path What
GET /rfqs All RFQs
GET /rfq/{id} RFQ header + lines + received quotes + invites
POST /rfq Create an RFQ
POST /rfq/{id}/invite · /send Invite a vendor (magic link) / send the RFQ
GET /rfq/{id}/compare Side-by-side supplier comparison matrix
POST /supplier-quotes/{id}/accept Accept a supplier quote → drafts a PO
GET / POST /supplier/respond/{token} Supplier views / submits a quote (no account)
POST /supplier/signup · /login · /account/history Optional persistent supplier login + history

Warehouse & work-orders (20)

Warehouse — warehouse (/warehouse)

Method Path What
GET /warehouse/levels On-hand / reserved / available per item × location
GET /warehouse/low-stock Items at/below their reorder point
GET /warehouse/dashboard Inventory dashboard aggregate (value by material type & location, low/negative, currency)
GET / POST /warehouse/locations, PATCH /{id} Manage stock locations
POST /warehouse/events Append a stock event (receive/consume/adjust/transfer…)

Work orders — workorders (/work-orders)

Method Path What
GET / POST /work-orders List / create fabrication jobs
GET /work-orders/{id} Work-order detail + cutting-list BOM
POST /work-orders/{id}/status Advance the stage (cutting→…→delivered)
POST /work-orders/{id}/bom Add a BOM/cutting-list line
POST /work-orders/{id}/seed-from-quote Seed the cutting list from a quote
POST /work-orders/{id}/reserve · /consume Reserve / consume materials against the ledger

Approvals & intake — approvals (/approvals), intake_warehouse

Method Path What
GET /approvals Pending draft-and-approve items
POST /approvals/{id}/approve · /reject Execute / discard a draft
POST /approvals/reorder Open a reorder-PO draft for the human queue
POST /intake/warehouse Webform/agent intake → normalised stock/job effect

CRM & client portal (8)

CRM (Attio) — crm

Method Path What
POST /attio/deals/{id}/sync Sync an Attio deal
POST /projects/{id}/attio/stage · /note Push a deal stage / append a note
POST /deal-registrations Register a partner-channel deal
POST /deal-registrations/{id}/won Mark a registered deal won

Client portal — client_portal

Method Path What
POST /projects/{id}/client-portal/issue Issue a client magic link for a project
GET /portal/{token} Client views the quote (no account)
POST /portal/{token}/accept-quote Client approves the quote

Imports, integrations & webhooks (17)

Historical import — historical_import (/imports)

Method Path What
GET / POST /imports List / upload a historical quote/bill (CSV/Excel/PDF)
GET /imports/{id} · /candidates Import status / fuzzy SKU-match candidates
POST /imports/candidates/{id}/resolve Resolve a match (Link / New SKU) → price observation

Xero — integrations_xero (/integrations/xero)

Method Path What
GET /integrations/xero/authorize · /callback OAuth connect flow
GET /integrations/xero/items · /contacts Read Xero items / contacts (dry-run)

Inbound webhooks — webhooks (/webhooks)

Method Path What
GET / POST /webhooks/whatsapp Meta handshake / inbound WhatsApp message
POST /webhooks/attio Attio deal events in
POST /webhooks/typeform Typeform intake in
POST /webhooks/pandadoc PandaDoc e-sign status in
POST /webhooks/xero Xero events → trigger payment reconcile
POST /webhooks/chatwoot Shop-floor/customer message → classify → warehouse/work-order effect
POST /webhooks/{provider} Generic verified webhook spine

Admin & ops (10)

Method Path What Router
GET /admin/margin-tracker Margin per quote/project admin
POST /admin/margin-rules Set margin rules admin
POST /admin/sku-overrides Per-SKU cost overrides admin
POST /projects/{id}/designer Assign a designer to a project admin
POST /admin/users/{id}/channels Set a user's notification channels admin
GET /admin/outbox Outbound integration-outbox browser (by provider + status) admin
POST /admin/outbox/{id}/retry Reset a failed/stuck outbox row to pending admin
POST /admin/webhooks/{event_id}/replay Replay a received webhook event admin
GET /forecast/pipeline Weighted sales pipeline + expected margin forecast
GET /healthz Liveness probe (unauthenticated) health

Generated from the route definitions in backend/api/ on 2026-06-14 (193 endpoints). The live /docs is always authoritative for exact schemas.