Manufacturing OS endpoints
Conventions as in §31. All paths are under /api/v1.
Comments and people
| Method & path | Body / query | Permission |
|---|---|---|
GET /comments?table_key=&row_id=&include_resolved=1 | threads of a table (or one row) | the table's read permission |
POST /comments | table_key, row_id, column_key?, row_label?, body (mentions @Display Name notify) | the table's read permission |
PATCH /comments/:id | body? and / or resolved? | author or settings.manage |
DELETE /comments/:id | — | author or settings.manage |
GET /directory/users | active people: id, display_name (for @mentions and owners) | any signed-in user |
Fields
| Method & path | Body / query | Permission |
|---|---|---|
GET /forms/:id/records?keys=api · GET /forms/:id/records/:rid?keys=api | record data keyed by API name | forms.read |
POST /forms/:id/records?keys=api · PUT …/:rid?keys=api | data keyed by API name (or by field id without the query) | forms.write |
PATCH /ui-config | fields: { items: { standard_cost: { label?, order?, help?, hidden? } } } | settings.manage |
Schedules
| Method & path | Body / query | Permission |
|---|---|---|
GET /schedules · GET /:id | — | workflows.manage |
GET /schedules/targets | the modules and forms an update may target, with their writable fields | workflows.manage |
POST /schedules | name, description?, is_active?, cadence { kind: once\|interval\|daily\|weekly\|monthly, … }, action { kind: update_fields\|run_function\|import_csv, … } | workflows.manage |
PATCH /schedules/:id | any of the above | workflows.manage |
POST /schedules/:id/run | runs now → the run | workflows.manage |
GET /schedules/:id/runs | the run log (newest first) | workflows.manage |
DELETE /schedules/:id | — | workflows.manage |
Cadences: { kind: "once", at } · { kind: "interval", every_minutes, from?, to? } · { kind: "daily", time, from?, to? } · { kind: "weekly", days: [1,3], time, from?, to? } · { kind: "monthly", day, time, from?, to? }. Actions: { kind: "update_fields", target: { kind: "module", module } | { kind: "form", form_id }, condition: { match, conditions[] }, set: [{ field, value }] } · { kind: "run_function", function_id, args } · { kind: "import_csv", import_id, batch_size }.
Imports
| Method & path | Body / query | Permission |
|---|---|---|
GET /imports/targets | targets (built-in sections and custom forms) with their fields | signed in |
GET /imports · GET /:id | imports of the workspace / one import with its counts | the target's write permission |
POST /imports | JSON { target: { kind: "module", module } \| { kind: "form", form_id }, file_name, content, delimiter? } or multipart file + target | the target's write permission |
PUT /imports/:id/mapping | { columns: { "<csv header>": "<field key>" }, options: { update_existing, key_field } } → validates every row | the target's write permission |
GET /imports/:id/rows?status=invalid | rows with their messages | the target's write permission |
POST /imports/:id/start | ≤ 200 valid rows: imports now; more: creates the schedule and returns it | the target's write permission |
POST /imports/:id/cancel | — | the target's write permission |
GET /imports/:id/errors.csv | the failed rows as CSV | the target's write permission |
DELETE /imports/:id | — | the target's write permission |
CRM
| Method & path | Body / query | Permission |
|---|---|---|
GET /leads?status=&search= · GET /:id | — | sales.read |
POST /leads · PATCH /:id · DELETE /:id | name, company?, email?, phone?, source?, status?, estimated_value?, owner_user_id?, notes? | sales.write |
POST /leads/:id/convert | customer_id? (attach to an existing customer), opportunity? { name, amount?, expected_close? } → { lead, opportunity } | sales.write |
GET /opportunities?stage=&customer_id=&search= · GET /:id | — | sales.read |
GET /opportunities/pipeline | per stage: count, amount, weighted | sales.read |
POST /opportunities · PATCH /:id · DELETE /:id | customer_id, name, stage?, amount?, probability?, expected_close?, owner_user_id?, lead_id?, notes? | sales.write |
POST /sales-orders | … plus opportunity_id? — confirming the order marks the deal won | sales.write |
Shipments, invoices, payments, vendor bills
| Method & path | Body / query | Permission |
|---|---|---|
GET /shipments?status=&sales_order_id= · GET /:id | — | sales.read |
GET /shipments/outstanding/:orderId | per line: line_id, item_id, outstanding | sales.read |
POST /shipments | sales_order_id, warehouse_id, ship_date, carrier?, tracking_no?, notes?, lines?[{ sales_order_line_id, quantity }] (omit lines = everything outstanding) → DN-… | sales.write |
POST /shipments/:id/ship | { idempotency_key } → { shipment, movement, order_status } (posts ISS-…) | stock.post |
POST /shipments/:id/cancel | — | sales.write |
GET /invoices?status=&customer_id=&sales_order_id= · GET /:id | — | sales.read |
GET /invoices/summary | open, overdue, paid_month, count_open | sales.read |
GET /invoices/:id/pdf | the PDF | sales.read |
POST /invoices · PUT /:id (draft) | customer_id, sales_order_id?, shipment_id?, invoice_date, due_date?, tax_rate?, customer_reference?, notes?, lines[{ item_id?, description, quantity, unit_price }] → INV-… | sales.write |
POST /invoices/:id/issue · /void | — | sales.write |
POST /invoices/:id/payments | amount, paid_on, method?, reference?, notes? → PAY-…; status follows the balance | sales.write |
DELETE /invoices/:id/payments/:paymentId | — | sales.write |
GET /vendor-bills?status=&vendor_id=&purchase_order_id= · GET /:id | — | purchasing.read |
POST /vendor-bills · PUT /:id (draft) | vendor_id, purchase_order_id?, bill_date, due_date?, vendor_invoice_no?, tax_rate?, notes?, lines[…] → BILL-… | purchasing.write |
POST /vendor-bills/:id/approve · /void | — | purchasing.write |
POST /vendor-bills/:id/payments · DELETE …/:paymentId | amount, paid_on, method?, reference?, notes? → VPAY-… | purchasing.write |
Quality
| Method & path | Body / query | Permission |
|---|---|---|
GET /inspections?result=&item_id= · GET /:id | — | jobs.read |
POST /inspections · PUT /:id · DELETE /:id | source_type?, source_ref?, item_id, quantity_inspected, quantity_passed?, quantity_failed?, result, inspected_on, inspector?, checklist?[{ point, ok, note? }], notes? → INS-… | jobs.write |
GET /ncrs?status=&severity= · GET /:id | — | jobs.read |
POST /ncrs · PATCH /:id · DELETE /:id | title, description?, item_id?, inspection_id?, source_ref?, severity?, quantity?, root_cause?, containment?, disposition?, owner_user_id?, due_date? → NCR-… | jobs.write |
POST /ncrs/:id/status | { status } along the state machine | jobs.write |
GET /capas?status=&ncr_id= · GET /:id | — | jobs.read |
POST /capas · PATCH /:id · DELETE /:id | title, type?, ncr_id?, description?, actions?, owner_user_id?, due_date?, effectiveness_check? → CAPA-… | jobs.write |
POST /capas/:id/status | { status } along the state machine | jobs.write |
Errors follow §42: a wrong step is invalid_transition (409), delivering more than is outstanding or paying more than the balance is validation_failed (400), and a missing document is not_found (404).
Last updated