Endpoint reference
The tables below are a quick scan of the routes and filters. For full request/response schemas, the interactive explorer is the richer view.
OpenAPI spec
Section titled “OpenAPI spec”The full machine-readable contract is served publicly (no auth, no shop data) at:
GET https://assemblified.com/api/v1/openapi.jsonPoint Postman, Insomnia, or any OpenAPI 3.1 client at that URL to generate a typed client or browse every parameter and response shape.
Endpoints
Section titled “Endpoints”| Method | Path | Scope | What it does |
|---|---|---|---|
GET | /api/v1/raw-materials | read | List raw materials (filters: search, usageFilter, originFilter, vendorFilter (repeatable), sortBy, sortOrder, page, pageSize) |
GET | /api/v1/raw-materials/{variantId} | read | One material; ?includeConnections=true adds the BOMs + assembly bills that use it |
PATCH | /api/v1/raw-materials/{variantId} | write | Edit fields — virtual (VMAT-*) materials only |
GET | /api/v1/raw-materials/{variantId}/inventory | read | Real per-location stock (?locationIds= repeatable) — live from Shopify for Shopify-linked materials |
PATCH | /api/v1/raw-materials/{variantId}/inventory | write | Set per-location stock — virtual (VMAT-*) materials only |
GET | /api/v1/raw-materials/{variantId}/residual | read | Per-location fractional remainders (?locationIds= repeatable) — bookkeeping, not sellable stock |
GET | /api/v1/raw-materials/{variantId}/preassembled | read | Per-location pre-assembled stock — finished units already built (?locationIds= repeatable) |
GET | /api/v1/raw-materials/{variantId}/commitments | read | Per location, how much is spoken for: open order reservations and safety-stock holds, with who holds them (?locationIds= repeatable) |
GET | /api/v1/raw-materials/{variantId}/shelf-allocation | read | Per location, how many units are embedded in pre-assembled stock on the shelf, with the parents that hold them (?locationIds= repeatable) |
GET | /api/v1/raw-materials/{variantId}/work-order-allocation | read | Per location, how many units open work orders have picked and still have to pick, with the work orders behind it (?locationIds= repeatable) |
GET | /api/v1/bills-of-materials | read | List bills of materials (filters: search, statusFilter, sortBy, sortOrder, page, pageSize) |
GET | /api/v1/bills-of-materials/{id} | read | One BOM with its fully hydrated recipe — raw materials, recursive assembly bills, cost factors |
GET | /api/v1/bills-of-materials/{id}/buildable | read | The computed per-location max-buildable (?locationIds= repeatable) |
GET | /api/v1/bills-of-materials/{id}/location-rules | read | The per-location rules configured on the BOM: what it does at each location and which materials change there |
GET | /api/v1/assembly-bills/{id}/preassembled | read | The same read for an assembly bill, keyed by its assembly id |
GET | /api/v1/bill-versions/{ownerType}/{ownerId} | read | The index of one bill’s saved versions (ownerType is bom or sub_assembly; ?limit= 1–20, ?offset=) |
GET | /api/v1/locations | read | Your Shopify locations — the id → name resolver every ?locationIds= keys on |
GET | /api/v1/assignees | read | The people a work order can be assigned to (?includeInactive=true adds retired ones) |
GET | /api/v1/work-orders | read | List work orders with their filter facets (filters: q, status, locationId, assignedTo, sourceType, tags, sortBy, sortDir, page, pageSize) |
GET | /api/v1/work-orders/{id} | read | One whole work order (?includeItemConsumption=true adds the per-item consumption plans) |
GET | /api/v1/work-orders/{id}/material-plan | read | Its material lines, the contributions behind them, the merged consumption plan and the cost block |
GET | /api/v1/work-orders/{id}/build-runs | read | Its build-run history |
PATCH | /api/v1/work-orders/{id} | write | Edit the header — requires expectedUpdatedAt |
PATCH | /api/v1/work-orders/{id}/transition | write | Move it to another state — exactly one of to / direction, plus expectedUpdatedAt |
PATCH | /api/v1/work-orders/{id}/build-runs | write | Start a build run — this moves real stock. Enhanced plan; send your own buildRunId |
GET | /api/v1/order-bom-breakdown | read | BOM breakdowns for 1–50 orders in one call (?ids= repeatable and/or comma-separated) — partial success; ?locationId= computes them from a single location’s recipes |
GET | /api/v1/order-bom-breakdown/{id} | read | One order’s BOM breakdown — what a warehouse must pack (?locationId= optional) |
GET | /api/v1/openapi.json | public | The machine-readable spec — no auth required |
sortBy on the list accepts productName (default), variantName, or inventoryQuantity; an unrecognized value is ignored and the default productName ordering is used.
Location ids
Section titled “Location ids”Every endpoint that takes ?locationIds= expects the bare numeric location id — 101176672579, not
the gid://shopify/Location/101176672579 form. GET /api/v1/locations is the resolver: it returns both
spellings per location plus the name, and pages your whole location list (no cap). Two rules hold across
all of them:
- Omitting
locationIdsmeans every location — an empty list is the same as leaving it out. - A scope that matches nothing reports
0, never a shop-wide figure. If you ask “how many are pre-assembled at location X” and nothing is stocked there, the honest answer is zero at X.
Pre-assembled stock vs. residual remainders
Section titled “Pre-assembled stock vs. residual remainders”Two per-location reads that are easy to confuse:
- Pre-assembled (
…/preassembled) is real, countable stock: finished units already built and sitting on the shelf, which an order consumes before any component is touched. Finished goods and assembly bills share one table for it, which is why the two routes return the same shape. Each route’s path id is the id that stock is tracked under, and it matches the namespace it sits in — a finished good is stocked against the Shopify variant it sells as, so read it at/raw-materials/{variantId}/preassembled(the same id its…/inventoryand…/residualsiblings take); an assembly bill is stocked against its assembly id, so read it at/assembly-bills/{id}/preassembled. - Residual (
…/residual) is not stock at all. When a recipe consumes a fractional quantity, whole units are what Shopify can hold, so the leftover fraction is parked as a residual — three 0.4-unit builds add up to one whole unit plus 0.2 carried, instead of losing the fraction. Two kinds are reported side by side because they move independently:buildRun(work orders and order execution) andsafetyStock(reservations). Never add residuals to an availability number.
Per-location commitment and allocation reads
Section titled “Per-location commitment and allocation reads”Three reads answer “what is this material already spoken for?” from three different directions. None of them is availability, and none may be subtracted from a stock figure — use …/inventory for stock. All three take the same repeatable ?locationIds=, and all three return empty levels and zero totals for a material nothing touches (a valid answer, not an error).
| Route | What it counts |
|---|---|
…/commitments | Two numbers per location: orders — the open quantity of order reservations — and safetyStock — what active safety-stock reservations hold. Each level also names who holds the units: the orders behind the first, and the bill behind each safety-stock hold. |
…/shelf-allocation | How many units are already built into pre-assembled stock sitting on a shelf, for every parent that consumes the material at any depth, waste included. Only available shelf units count — committed ones are reported by …/commitments, so nothing is double-counted. Each level lists the contributing parents. |
…/work-order-allocation | How many units your open work orders have already picked (picked) and still have to pick (remaining), with allocated their sum. Open means every status except completed and cancelled. Each level lists the contributing work orders; demand from a work order with no location is reported separately under totals.unlocated. |
The holder lists are capped at the 20 biggest per location, with a count of the rest — the sums stay uncapped, so a total is always the whole truth even when the list beside it is trimmed.
curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/raw-materials/VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f/work-order-allocation?locationIds=74001236152"Shopify-managed materials are read-only in v1
Section titled “Shopify-managed materials are read-only in v1”Every GET works for both origins — Shopify-linked and virtual. The two raw-material PATCH endpoints accept only virtual materials (ids starting VMAT-). A PATCH against a numeric Shopify variant id returns 400 INVALID_INPUT with a “read-only in API v1” message, before anything is changed. This is deliberate: fields like name, sku, price, and cost on Shopify-linked materials are mirrored from Shopify, so a local API edit would be silently reverted by the next product update. Editing those belongs in the Shopify admin (or a future API version with true write-back).
This rule is about materials. The three work-order PATCH endpoints take a work-order id and are not constrained by it — see Work orders below.
Examples
Section titled “Examples”List raw materials
Section titled “List raw materials”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/raw-materials?originFilter=virtual&usageFilter=unused&pageSize=25"{ "data": { "items": [ { "variantId": "VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f", "productId": "VMAT-PROD-2a9c8b7d-6e5f-4a3b-8c1d-0e9f8a7b6c5d", "inventoryItemId": "VMAT-INV-5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f", "productName": "Oak board 20 mm", "variantName": "120 x 60 cm", "sku": "OAK-20-120", "vendor": "Holzwerk GmbH", "unit": "pcs", "unitCost": 12.5, "unitPrice": 0, "inventoryQuantity": 240, "isVirtual": true, "bomUsageCount": 0, "subAssemblyUsageCount": 0 /* … specifications, imageUrl, isNonEssentialMaterial, weightValue, weightUnitId, productType, productCategory … */ } ], "totalCount": 7, "page": 1, "pageSize": 25, "totalPages": 1, "availableVendors": ["Holzwerk GmbH", "Acme Supplies"] }, "meta": { "requestId": "…", "apiVersion": "1.2" }}Get one material (with connections)
Section titled “Get one material (with connections)”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/raw-materials/VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f?includeConnections=true"Returns data.material (same fields as a list row, minus the usage counts) plus data.connections with boms and subAssemblies arrays — each entry names the BOM / assembly bill, the quantity of this material it uses, and its location. Works for Shopify-linked materials too (numeric id in the path).
Update a virtual material
Section titled “Update a virtual material”curl -s -X PATCH \ -H "Authorization: Bearer $ASMK_TOKEN" -H "Content-Type: application/json" \ -d '{ "unitCost": 13.1, "vendor": "Holzwerk GmbH" }' \ "https://assemblified.com/api/v1/raw-materials/VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f"Returns data.material — the full updated row. Only the fields you send change; the editable field list is in Conventions.
Read per-location inventory
Section titled “Read per-location inventory”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/raw-materials/VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f/inventory"{ "data": { "variantId": "VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f", "origin": "virtual", "totalAvailable": 240, "cachedQuantity": 240, "levels": [ { "locationId": "74001236152", "available": 190 }, { "locationId": "74001268920", "available": 50 } ] }, "meta": { "requestId": "…", "apiVersion": "1.2" }}For a Shopify-linked material (numeric id), origin is "shopify", the levels are a live Shopify read, and each level row additionally carries a locationName. Virtual materials return locationId + available only — no locationName.
Set per-location inventory (virtual only)
Section titled “Set per-location inventory (virtual only)”curl -s -X PATCH \ -H "Authorization: Bearer $ASMK_TOKEN" -H "Content-Type: application/json" \ -d '{ "updates": [ { "locationId": "74001236152", "absolute": 200 } ] }' \ "https://assemblified.com/api/v1/raw-materials/VMAT-VAR-7f3d2c1a-9b4e-4c8d-a2f6-5e1b0d9c8a7f/inventory"Returns the per-row batch envelope (results / okCount / failedCount / skippedCount). Each row carries exactly one of absolute (retry-safe — prefer it) or delta; full body semantics in Conventions. Every adjustment is recorded in the material’s adjustment history.
Bills of materials (read-only)
Section titled “Bills of materials (read-only)”The four bills-of-materials endpoints expose your BOMsBill of MaterialsA bill of materials tells Assemblified how to build one unit of a finished good. When a customer orders the finished-good variant, Assemblified deducts the right component quantities from inventory automatically.
Read more →
— finished goods and their recipes, the computed max-buildable, and the per-location rules configured on a bill. They are read-only in this version.
List bills of materials
Section titled “List bills of materials”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/bills-of-materials?statusFilter=active&pageSize=25"Returns data.items (the projected BOM rows) plus the pagination fields and a stats block (total, active, inactive, totalValue, avgCost, shopifyLinked) aggregated over the full BOM set.
Get one BOM (the hydrated recipe)
Section titled “Get one BOM (the hydrated recipe)”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/bills-of-materials/BOM-1748441466223"{ "data": { "bomId": "BOM-1748441466223", "status": "active", "name": "Oak Table", "productId": "8613244518724", "variantId": "45217109934404", "sku": "TABLE-OAK", "price": 499, "totalRawMaterialCost": 96.5, "totalSubAssemblyCost": 41.0, "totalCost": 137.5, "directCostFactorCost": 26.7, "preAssembledQuantity": 3, "rawMaterialReferences": [ { "nodeId": "VMAT-VAR-…", "quantity": 4, "wastePercentage": 5, "node": { "productName": "Oak board 20 mm", "unit": "pcs", "unitCost": 12.5 } } ], "subAssemblyReferences": [ { "nodeId": "ASM-…", "quantity": 2, "node": { "assemblyName": "Table leg", "unitCost": 20.5, "rawMaterialReferences": [], "subAssemblyReferences": [] } } ], "costFactorReferences": [ { "costFactorId": "CF-…", "quantity": 0.5, "node": { "name": "Assembly labour", "kind": "labour", "unit": "hour", "unitCost": 40 } } ] }, "meta": { "requestId": "…", "apiVersion": "1.2" }}Sub-assemblies nest recursively — each subAssemblyReferences[].node carries its own rawMaterialReferences and subAssemblyReferences, so one call returns the complete tree.
Compute max-buildable
Section titled “Compute max-buildable”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/bills-of-materials/BOM-1748441466223/buildable"{ "data": { "bomId": "BOM-1748441466223", "variantId": "45217109934404", "hasSellableSplit": false, "perLocation": [ { "locationId": "74001236152", "locationName": "Main warehouse", "maxBuildable": 24, "sellable": 24, "limitingComponents": [ { "nodeId": "VMAT-VAR-…", "name": "Oak board 20 mm — 120 x 60 cm", "origin": "virtual", "quantityPerUnit": 4, "wastePercentage": 5, "isNonEssential": false, "maxUnitsByThisComponent": 24, "availableAtLocation": 96 } ] } ], "totals": { "maxBuildable": 24, "sellable": 24 }, "globalFallback": false }, "meta": { "requestId": "…", "apiVersion": "1.2" }}This is the same number the admin UI’s Max Buildable column shows: the full component tree against live Shopify raw-material levels, virtual levels, and nested pre-assembled assembly-bill stock — waste included, non-essential components excluded. Notes:
sellablerespects assembly bills flagged only consume pre-assembled; it differs frommaxBuildableonly whenhasSellableSplitistrue.limitingComponentslists the three tightest leaves of the SAME full-tree calculation that producedmaxBuildable, most constraining first. A leaf can be a material anywhere in the recipe (including inside an assembly bill), andoriginreadspreassembledwhen a cut-off assembly bill’s pre-assembled stock is what binds (itsnodeIdis thensubassembly:<assemblyId>).maxUnitsByThisComponentis that leaf’s exact capacity and equalsmaxBuildableon the first row;quantityPerUnitis the effective per-unit need, waste and nested consumption included.- When the BOM’s variant has no per-location Shopify data,
totalsfalls back to a single global computation andglobalFallbackistrue. - This is the most expensive read on the surface (it reads live Shopify levels) — cache the result rather than polling it.
Order BOM breakdown (read-only)
Section titled “Order BOM breakdown (read-only)”The two order-bom-breakdown endpoints answer the warehouse question: given an order, what exactly needs to be packed? Each breakdown lists the order’s BOMBill of MaterialsA bill of materials tells Assemblified how to build one unit of a finished good. When a customer orders the finished-good variant, Assemblified deducts the right component quantities from inventory automatically.
Read more →
lines with their component materials — assembly billsAssembly billThe recipe for an intermediate component you build and then use inside other bills — a lid, a wick assembly, a pre-wired harness. It keeps its own pre-assembled stock and can be a work order item in its own right.
Read more →
expanded down to leaf raw materials, waste included, quantities already multiplied by the ordered quantity — plus a cross-order totalMaterials summary and the non-BOM lines under otherItems.
The boms and totalMaterials portions are the same shape as the assemblified.material_requirements_json order metafield (see Shopify extensions) — built by the same code — so anything already consuming the metafield can switch to this endpoint unchanged. Unlike the metafield, the endpoint works for every order (the metafield writeback is an opt-in setting) and always reflects the order’s current line items.
Get one order’s breakdown
Section titled “Get one order’s breakdown”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/order-bom-breakdown/6234567890123"{ "data": { "orderId": "6234567890123", "orderName": "#1042", "generatedAt": "2026-08-03T12:00:00.000Z", "boms": [ { "bomId": "BOM-1748441466223", "bomName": "Oak Table", "bomImageUrl": null, "bomProductId": "8613244518724", "bomVariantId": "45217109934404", "bomSku": "TABLE-OAK", "orderQuantity": 2, "materials": [ { "productId": "VMAT-PROD-…", "variantId": "VMAT-VAR-…", "sku": "OAK-20-120", "title": "Oak board 20 mm - 120 x 60 cm", "productName": "Oak board 20 mm", "variantName": "120 x 60 cm", "specifications": null, "notes": null, "quantity": 8 } ] } ], "totalMaterials": [ { "variantId": "VMAT-VAR-…", "productId": "VMAT-PROD-…", "sku": "OAK-20-120", "title": "Oak board 20 mm - 120 x 60 cm", "productName": "Oak board 20 mm", "variantName": "120 x 60 cm", "specifications": null, "notes": null, "totalQuantity": 8, "imageUrl": null, "isVirtual": true, "unitCost": 12.5 } ], "otherItems": [ { "variantId": "45217109999999", "productId": "8613244599999", "sku": "GIFT-CARD", "title": "Gift card", "quantity": 1 } ] }, "meta": { "requestId": "…", "apiVersion": "1.2" }}The path id is a bare numeric Shopify order id (recommended). The full gid://shopify/Order/… form is accepted too, but must be percent-encoded when used in the path — its literal slashes would otherwise split the URL and return 404 (in the batch route’s ids query parameter it needs no encoding). materials[].quantity is already multiplied by orderQuantity (2 tables × 4 boards = 8); totalMaterials deduplicates across all BOM lines by variant. An order that contains no BOM products still returns 200 with boms: [] and its lines under otherItems — an unknown order id returns 404 NOT_FOUND.
Get breakdowns for up to 50 orders
Section titled “Get breakdowns for up to 50 orders”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/order-bom-breakdown?ids=6234567890123,6234567890124&ids=6234567890125"{ "data": { "items": [ { "orderId": "6234567890123", "…": "…" } ], "notFound": ["6234567890125"] }, "meta": { "requestId": "…", "apiVersion": "1.2" }}ids is repeatable and/or comma-separated (1–50 per call; more returns 400 INVALID_INPUT). The batch is partial-success: ids that can’t be resolved land in notFound and the call still returns 200 with every resolvable order — one request, one rate-limit token, regardless of how many orders it carries.
Work orders
Section titled “Work orders”Eight routes — four reads and three writes, plus the assignee list they reference. This is the largest resource family in v1, and the only one with writes that are not virtual-material writes.
List work orders
Section titled “List work orders”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/work-orders?status=in_progress&pageSize=25"Returns data.rows — flat rows, with no items, materials or build runs on them — plus total, hasMore and facets. The facets are the filter vocabulary for your shop counted over the unpaged result set (status, location, assignee and tag, each as { value, label, count }), so a client can render its filter controls without a second call.
Filters: q (free text over the name, the short id and the assignee’s name), status and tags (comma-separated, OR semantics), locationId, assignedTo (an assigneeId from GET /assignees, not a name), sourceType (flow, bom, sa, empty, orders). Sorting with sortBy + sortDir; paging with page (1-based) + pageSize (max 100).
Get one work order
Section titled “Get one work order”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/work-orders/wo_9c3f21d8-5a4e-4d2b-91c7-0f6b5a3e7d14"One work order, whole: the header, its items, materials and contributions, the merged consumption plan, build runs, QC reviews, rework items, documents, the conversation, the lifecycle events, the cost block and availableTransitions. Add ?includeItemConsumption=true for the per-item consumption plans (a second, heavier read).
warnings[] is recomputed on every read, never a stored flag — so a warning disappears the moment its cause does, and each one carries the remedy. That is the supported way to learn that a stock push is stuck; the build runs deliberately carry no internal sync columns.
Get the material plan
Section titled “Get the material plan”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/work-orders/wo_9c3f21d8-5a4e-4d2b-91c7-0f6b5a3e7d14/material-plan"Returns materials, contributions (which recipe row or manual addition each quantity came from), consumptionPlan (what comes off which shelf at which location) and cost. This is the existing plan, not a preview — read it before starting a build run.
List the build runs
Section titled “List the build runs”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/work-orders/wo_9c3f21d8-5a4e-4d2b-91c7-0f6b5a3e7d14/build-runs"Every pick, its items, the plan snapshot committed with it, and the completion or reversal that followed. Cheaper than reading the whole work order when the run history is all you want.
Edit the header
Section titled “Edit the header”curl -s -X PATCH \ -H "Authorization: Bearer $ASMK_TOKEN" -H "Content-Type: application/json" \ -d '{ "expectedUpdatedAt": "2026-09-01T09:12:44.000Z", "priority": "high", "assigneeId": "3f7c1e90-2b84-4a15-9d63-8e0a4c5f2b71" }' \ "https://assemblified.com/api/v1/work-orders/wo_9c3f21d8-5a4e-4d2b-91c7-0f6b5a3e7d14"Returns { workOrderId, updatedAt }. expectedUpdatedAt is required on all three writes — see Work-order PATCH semantics for the field lists and the optimistic-lock rule.
Move it to another state
Section titled “Move it to another state”curl -s -X PATCH \ -H "Authorization: Bearer $ASMK_TOKEN" -H "Content-Type: application/json" \ -d '{ "expectedUpdatedAt": "2026-09-01T09:12:44.000Z", "direction": "forward" }' \ "https://assemblified.com/api/v1/work-orders/wo_9c3f21d8-5a4e-4d2b-91c7-0f6b5a3e7d14/transition"Send exactly one of to (the target state) or direction (forward / back); both or neither is 400 INVALID_INPUT. The step itself is derived from the work order’s current state, so a client never needs the transition vocabulary. Returns { workOrderId, status, previousStatus, updatedAt, lifecycleEventId }. An illegal move is 409 CONFLICT with the blockers named.
Start a build run
Section titled “Start a build run”curl -s -X PATCH \ -H "Authorization: Bearer $ASMK_TOKEN" -H "Content-Type: application/json" \ -d '{ "expectedUpdatedAt": "2026-09-01T09:12:44.000Z", "buildRunId": "8b1f…", "items": [ /* … */ ] }' \ "https://assemblified.com/api/v1/work-orders/wo_9c3f21d8-5a4e-4d2b-91c7-0f6b5a3e7d14/build-runs"Returns the run with its items (buildRunId, shortId, status, the two updated-at tokens, and any negative-inventory warnings).
Assignees
Section titled “Assignees”curl -s -H "Authorization: Bearer $ASMK_TOKEN" "https://assemblified.com/api/v1/assignees"The people a work order can be assigned to, sorted by display name, each with usageCount (how many live work orders name them). Active rows only unless you pass ?includeInactive=true, which adds the retired ones — a retired person still resolves on the work orders that name them, but no new work order may be assigned to one.
These assigneeIds are what the work-order list’s assignedTo filter takes and what PATCH /work-orders/{id} writes to assigneeId. The list is read-only here; people are added and removed in the admin (Settings → Catalogues → Assignees) or through agent access.
Bill versions
Section titled “Bill versions”curl -s -H "Authorization: Bearer $ASMK_TOKEN" \ "https://assemblified.com/api/v1/bill-versions/bom/BOM-1748441466223?limit=20"The index of one bill’s saved versions, newest first. ownerType is bom for a finished good or sub_assembly for an assembly bill, and ownerId is that bill’s id — one index serves both kinds. Each row carries the change summary frozen onto it when it was saved (how many recipe fields, materials, per-location rules and overrides moved against the previous version), its content hash, what triggered it, and who saved it. Paging: limit (1–20) + offset, with hasMore.
pending counts versions that have been allocated but are not readable yet — which is why a page can hold fewer rows than you just saved.