Skip to main content

History

9/30/2026​

9/29/2026​

  • Added Department Shift Create, Update and Delete. startTime and endTime must be 24-hour HHmm; each availableEquipment[].equipmentId must be equipment in the shift's department, listed once, and equipmentName is filled from the equipment. Update replaces the whole shift except departmentId, which cannot change, so omitted fields are cleared. Update and Delete mark the latest schedule out of date; Delete answers 204 for a shift that does not exist or is already deleted. New endpoints — no existing behavior changes.

  • Added Department Shift List and Get. startTime and endTime are 24-hour HHmm; lengthOfShiftInMinutes counts an earlier endTime as overnight and is null when either time is invalid. availableEquipment is ordered by equipmentId, case-sensitively. List filters on ids, departmentIds (500 each) and name, sorts newest first unless Sort.Field names a top-level field (others are a 400), and omits deleted shifts, which Get returns with deleted: true. New endpoints — no existing behavior changes.

9/28/2026​

  • Added Sales Order Part Line Item Full Routing Input Material Create, Update and Delete, editing the input materials on a sales order line's own routing without changing the item's routing. A routing holds each material once, and routingStepId must be an operation on that routing; an update without it unlinks the operation. Edits repeat wherever the item recurs in the line's routing tree. The sales order must be Draft or Approved. They are not available to user-bound tokens. New endpoints — no existing behavior changes.

9/25/2026​

  • Changed Change Order Create to seed impactedRecords from every open document still carrying originalRevisionItem — a sales order or quote line with no disposition, a complete job as Finish As Is, any other job as Revision — and to apply the account's default change order task template, with due dates counted from the UTC day of requestedUtc. An omitted requestedUtc is stored as the account's current local day at UTC midnight. Seeding and the template apply happen only where change order updates are enabled; the request body is unchanged.
  • Added size and designation to Tool Get, Tool Create and Tool Update: free text up to 100 and 200 characters on every tool type, longer is a 400. Only threadPlugGage, threadRingGage, nptPlugGage, nptRingGage, plugGage, ringGage, setPlug, splineGage and attributeGage keep them; a save clears them on the rest. Existing writes change: a save clears measurementRangeMin, measurementRangeMax and their precisions on those nine types and on fixture, machine and weldingEquipment, which also lose accuracy and accuracyPrecision. Update replaces the whole tool, so omitting size or designation clears it.
  • Changed search on Tool List to also match size and designation, whitespace-insensitively. A search that reads as a plain number (0.75) or as two numbers joined by a dash (0-6, in either order) also matches tools whose measurementRangeMin–measurementRangeMax covers it, but only on tool types that keep a range: never the nine gage types that keep size, nor fixture, machine or weldingEquipment. Results can only grow for a given search; request and response shapes are unchanged.
  • Added itemId to the line items returned by Receipt List when includeReceiptLines is set: the part on a part line, and the item being processed on an outside-processing line. null on a fee line or an outside-processing line with no item. Addition-only — existing payloads gain the field but no field changes.
  • Added source to the rows returned by Inventory Transactions List: type, name, jobId and itemToMakeId, or null when no source was recorded. jobId is set on every transaction a job owns — its picks and returns, including those against a work-order operation, and items it put into inventory — and null otherwise. Addition-only.

9/24/2026​

  • Added change orders: Change Order List, Get, Create, Update and Delete, carrying number, customer, originalRevisionItem, newRevisionItem, status, requestedUtc, dueDateUtc, disposition, detail and read-only impactedRecords, which list rows omit. originalRevisionItem.id is required. Update replaces the header and never writes the impacted records or the tasks. Deleting an applied change order is a 400. Change order and task routes answer 404 until the surface is switched on for the account. New endpoints — no existing behavior changes.

  • Added tasks as their own resource: Task List, Get, Create, Update and Delete. Every task belongs to the change order named by relatedRecord, whose id is required on create and ignored on update; update is a full replacement. A sequence of 1 or more places the task at that step. completedBy is null on a completion made with an integration token, relatedRecordIds takes at most 1000 ids, and tasks carry no modification stamp. New endpoints — no existing behavior changes.

9/22/2026​

  • Corrected Item Vendor Update to record that it changed the vendor detail. The endpoint saved the new values but left the vendor's own modification timestamp untouched, and that timestamp is what the app reads to decide whether a quote or sales order line was priced from pricing that has since moved. A price changed through this endpoint therefore left every line priced from that vendor looking current, while the same edit made in the app flagged them. Request and response are unchanged, and the timestamp is not exposed on this API; what changes is that lines priced from a vendor updated here are now correctly reported as holding out-of-date pricing. Item Vendor Create does not set the timestamp, so a vendor added through the API still does not flag existing lines.

  • Corrected Vendor Patch. A patch document whose operations all target /externalReferences, including the from of a move or copy, no longer validates the vendor's other stored fields. A vendor holding a url without a scheme (www.vendor.com) or an empty vendorCode now answers 200 to such a patch; previously the request answered 400 naming that field. A patch that names any other field, or has no operations, still validates the whole vendor, as before.

9/21/2026​

  • Changed Customer Patch to validate name when an operation names /name, as Customer Create and Customer Update already do. A patched name is trimmed and must be 1 to 200 characters, so a blank or whitespace-only one is now rejected with a 400 instead of being stored; a padded name is stored trimmed rather than as sent. Only an operation whose path or from resolves to name triggers the check, however the pointer is spelled (name, /name/ and //name count as /name) — a patch touching other paths is unaffected, including on a customer whose stored name is already blank. Callers that patched blank names will start receiving the 400.

  • Corrected Customer Patch. A patch document with no operation under /customFields no longer validates the customer's stored custom fields against the current definitions, so a customer holding a value for a deleted definition, or a legacy key, can again be patched on name, externalReferences and the other fields; previously the request answered 400 naming that key. Operations under /customFields still validate every key they carry, and a patch that does not name them leaves the stored values exactly as they were.

  • Added PUT /work-orders/{workOrderId}/operations/{workOrderOperationId}/nesting-setup, replacing a work-order operation's nest with the parts[], plates[] and unplacedParts[] sent. Parts and sheet placements link by partNumber; two parts may not share one. The stored parts list is derived from the sheets, so the response carries the nest as stored, not an echo, plus validationIssues[], which never refuse the write. Server-owned fields the GET reports are ignored, nestingFile is kept, and an item object is accepted in place of its itemId. scrap is not accepted. Empty parts and plates clear the nest; a nest with a completed sheet repetition, posted inventory or recorded scrap answers 409. Not yet in the schema reference.

9/16/2026​

  • Added quantityToMake and quantityCompleted to the operations returned by Job Operation List, Job Item To Make Operation List, Get and Job Tracking. quantityCompleted is the higher of the count stamped when an operation completes and the running count operators bank while it is still in progress. Scrap does not reduce it, and it can exceed quantityToMake. On a continuous-flow routing quantityToMake is the operation's current requirement, not a fixed plan — it is rewritten as the preceding operation banks parts. Both are read-only: Update ignores them. Addition-only — existing payloads gain the fields but no field changes.
  • Added NCR Create — POST /ncrs, opening an NCR in status New and returning the same shape as NCR Get. type and detail are required; title, cause, reason and disposition are optional, and disposition must be one of the app's disposition values. jobId and/or itemId create the NCR's single impact: the job's customer and sales order are recorded from the job, and itemId defaults to the job's parent item. quantityImpacted (zero or greater) requires one of them; quantityImpactedDisposition is All, Partial (default) or Unknown, and All replaces the quantity with the job's quantity made. An unknown jobId or itemId is a 404. Requires Create NCR permission. New endpoint — no existing behavior changes.
  • Added CAPA Create — POST /capas, taking capaType (correctiveAction, preventiveAction, supplierIssue, safetyIssue), problemStatement, and optional rootCauseAnalysis and dueDate, and returning the new CAPA's id. The CAPA is created in the New status with no linked NCR, owner or tasks; dueDate defaults to one month after creation. Requires Edit CAPA permission. New endpoint — no existing behavior changes.

9/15/2026​

  • Changed Note Create to require permissions on user-bound tokens: View Sales Order, View Purchase Order, View Quote and View Invoice — all four, whatever parentType the note targets, because the endpoint is polymorphic and the gate is static, so it cannot narrow to the parent actually sent. A user-bound token missing any one of them now gets 403 where the call previously succeeded. Tenant-bound tokens are not gated and are unaffected.

  • Corrected price on Part Line Item Create Batch. A price sent for an item that carries a price break was replaced by the break's own price, so the line persisted at the item's catalogue figure and the response reported that figure rather than the one sent. The supplied price is now kept, and the line reports priceSource Custom instead of Item. Two cases still price the line themselves and ignore a supplied value, as they do in the app: a margin-priced break, and a break with quantity breakpoints. An item with no price break was already honouring the sent price and is unchanged, as is the single-item Create, which applies price after the line exists. A batch that sends no price still takes the item's price.

  • Added dueDate to Quote Get, Quote List, Quote Update and Quote Patch; Quote Create ignores it without an error. Update never clears it — an omitted or null value keeps the stored date — so only a patch operation naming /dueDate with null clears one. Send the calendar date (2026-04-17); any time or UTC offset is ignored and the value is stored at midnight UTC. Update rejects a value outside 2000-01-01 to 2099-12-31 with 400; patch does not range-check. A quote already Sent rejects the write. Addition-only — existing payloads gain the field but no field changes.

9/14/2026​

  • Changed Job Tracking Timer Start and Stop to accept operations grouped under a work order, which previously answered 400. Starting a timer on such an operation starts the work-order operation's timer, which covers every job operation grouped under it; userId attributes it the same way it does a job timer, and a repeated start for the same user adds no timer. Stopping a work-order timer, or one of the per-job timers it holds, stops the whole work-order timer and every per-job timer under it. Those per-job timers list on Job Tracking Timer List with workOrderId null, so they are not distinguishable there from plain job timers. On both endpoints a userId or timerId that refers to a deleted record now answers 404 rather than being acted on. Operations not grouped under a work order are otherwise unaffected.
  • Added salesOrderLineItemId to the rows returned by Reporting Sales Order Lines List: the line item's own id, as returned by Sales Order Line Item List. It is not unique per row, and only that type-agnostic list resolves it, because this report also carries tax, fee, discount, shipping-charge and refund rows. salesOrderLinePrimaryKey identifies the report row rather than a line item; its description previously said otherwise. Addition-only — existing payloads gain the field but no field changes.
  • Added POST /work-orders, creating a work order from job operations. Send operations[] (1–50), each with jobOperations[] of jobId and jobOperationId (500 across the request) and optional additionalInstructions, estimatedSetupTimeSeconds and estimatedRunTimeSeconds; the work order takes optional name, status, priority and productionDueDateUtc. status defaults to needsReview and accepts needsReview or approved; priority defaults to moderate. A job operation already on a work order answers 409 naming that work order. Returns the new id. Not yet in the schema reference.
  • Changed salesOrderModifiedUtc on Reporting Sales Order Lines List to serialize with a trailing Z (2026-09-14T09:24:32.5574251Z), as the other UTC timestamps on this API do. The instant is unchanged — it was always UTC, as the field name and description say — only the offset marker is new. A consumer that already treated it as UTC sees no difference; one that parsed it as local time was reading it wrong and will now read it right. Sending a previously received value back as modifiedAfterUtc, with or without the Z, continues to work.

9/13/2026​

  • Corrected subtotal on Invoice Get, Invoice List, Invoice Update and Invoice Patch. It is the sum of the line items the invoice bills, in primary currency, before tax, the discount, the deposit and progress-billing adjustments, and any refund — a deposit invoice reports its deposit lines. Integrations keying on subtotal will see it rise by the discount.
  • Corrected subtotal on Sales Order Get, Sales Order List, Sales Order Update and Sales Order Patch. It is the sum of the line items the order bills, before tax, the discount and any refund; child lines of a blanket-order line are excluded. Integrations keying on subtotal will see it rise.

9/11/2026​

  • Made Attachment List available to custom pages. A user-bound token sees only attachments whose owner entity it holds view permission for — the rows are excluded in the query itself, ahead of skip/limit, so a page fills completely — and an owner it may not view yields 200 with an empty list rather than 403. Owner types the permission map does not cover are never returned to a user-bound caller. Tenant-bound API keys are unaffected.
  • Fixed Attachment List paging: sort (by default, name ascending) now decides which attachments fall on each page. Previously each page was cut from the matching attachments in no defined order and only then sorted, so paging through a list could repeat or skip attachments.
  • Changed Item Routing Input Item Create, Item Routing Input Item Create Batch and Item Routing Operation Item Create to answer 400 when a newly added input item is the item itself, another revision sharing its routing, or an item that consumes any of those, directly or through intermediate items — a circular bill of materials. The message names each item in the loop; nothing is written. Lines the routing already carries are not re-checked. Callers that made such writes now receive the 400.
  • Added Quote PDF — GET /quotes/{quoteId}/pdf, returning application/pdf as Quote_{number}.pdf, or Quote_{number}_{revision}.pdf for a quote carrying a revision letter. The PDF reflects the quote's current state and the tenant's PDFs & Emails settings at the time of the request; it is not a previously generated or emailed copy. Requires View Quote permission. Returns 404 if the quote does not exist or has been deleted — unlike Quote Get, which still returns a deleted quote. New endpoint — no existing behavior changes.

9/10/2026​

  • Changed the email rule on customer contacts. Customer Contact Create and Update, and the contact block on Quote Create and Sales Order Create, now accept only a single well-formed mailbox address: an ASCII local part, one @, and a domain with at least two labels. Display names, angle brackets, quotes, embedded whitespace, comments, IP literals and non-ASCII characters are rejected with the same 400 and Email model-state message as before. Strings are still trimmed on the way in, so surrounding whitespace is dropped and a blank email is treated as omitted, the same as null. Previously anything with one @ and text on both sides was stored, so a payload sending Name <[email protected]> or a dotless domain will start failing.
  • Changed how Tools List filters treat reference gages (tools with calibration frequency None), as part of introducing in-house verifications for them. calibrationStatuses now matches every tool on its active track: a scheduled tool on its latest calibration, a reference gage on its latest verification — so a gage with no verifications now matches notApplicable, where before it matched no status at all. reference is now AND-combined with the other filters (it narrows to gages) instead of OR-adding gages to the status results. The due-window filters (isOverdue, due7Days, due30Days, dueWithinDays) now also match a cadenced reference gage on its verification due date; a gage with no cadence has no due date and still never matches. Tool responses gain read-only verificationFrequency, verificationInterval, lastVerificationDateUtc and nextVerificationDateUtc. Verification records themselves are not exposed on the public API: tool-calibration list/get/update serve calibrations only.
  • Added inclusive whole-day date-range filters to ten list endpoints. Every bound is optional and applies on its own, and a bound outside 2000–2099 is rejected with a 400. Addition-only — existing requests are unaffected.
    • Plain calendar dates, used exactly as entered: orderDateFrom/orderDateTo on Purchase Order List; productionDueDateFrom/To on Job List; quotedDateFrom/To on Quote List; nextCalibrationDateFrom/To on Tool List. A quote that was dated by sending it carries the send moment, so it is filtered on the UTC calendar.
    • Shop-timezone days, so a record stamped at 6pm on the last of the month falls in that month: completedOnFrom/To on Job List and Work Order List; actionDateFrom/To on Inventory Event List; createdFrom/createdTo on CAPA List and NCR List.
    • issueDateFrom/issueDateTo on Invoice List split by how the date was set: a date you typed is used as entered, and a date stamped by sending the invoice is read as a shop day — the same split the month-end accounting report uses.
    • stoppedFrom/stoppedTo on Reporting Time Clock List are UTC days, like the startedFrom/startedTo beside them. An entry that has not been stopped never matches.
    • On CAPA List and NCR List the existing createdUtc filter is unchanged and combines with the new pair rather than being replaced by it. Use createdFrom to ask for a day and createdUtc to resume from an instant.
  • Corrected number on Receipt Get, Receipt Update and Receipt Patch. It counted an order's uncommitted receiving batch, so a committed receipt could report one higher, and the same receipt could report different numbers on two reads. All three now count committed receipts only, matching Receipt List — which in turn no longer renumbers when receiptIds narrows the result. An uncommitted batch fetched by id reports 0 rather than 1. Integrations keying documents on number may see it fall by one.
  • Added customerTypeId and customerTypeName to the customer returned by Customer Get and Customer List. Both are read-only — the type is assigned in the app: Customer Create and Update ignore them, and neither is a valid Patch path. A customer with no type carries null in both. Addition-only — existing payloads gain the fields but no field changes.
  • Changed Reporting Sales Order Lines List to answer 400 when salesOrderStatus is not one of the status labels the rows carry — Draft, Needs Approval, Approved, In Progress, Complete, compared ignoring case. Previously any other value, including the camelCase enum names the sales-order endpoints use such as inProgress, matched nothing and returned an empty page that looked like a real answer. The error names the field and lists the accepted values. Requests that already send a valid label are unaffected.
  • Added Nesting Work Package Manifest — POST /nesting/work-package-manifest, the cut list for 1–500 job operations sent as jobOperations[] of jobId, jobOperationId and optional itemToMakeId (an operation id can repeat within a job). Each part carries quantity, dates, material and drawings[] — attachment ids for GET /attachments/{attachmentId}/download, with isOperationSpecific and ownerType (item drawings need View Item on user-bound tokens); an operation-tagged drawing hides item-level ones. material.name is always present; materialName and grade are null unless the material master carries them. Unresolved entries return in skipped as notFound, ambiguousJobOperation (resend with itemToMakeId) or noSystemOperation.

9/9/2026​

  • Changed the redirect that Attachment Download returns for a file over 20 MB: the signed storage URL now carries a Content-Type for a recognised extension (application/pdf for a .pdf; an unrecognised extension such as .SLDPRT carries none and storage serves the type stored on the file), and its Content-Disposition is signed per request rather than read from a header stored on the file. Previously both headers were whatever the last in-app preview or download had written onto the blob, so a consumer could receive application/octet-stream for a PDF, or a disposition left behind by another caller. Files of 20 MB or less are still streamed directly with the same file name and type as before. Response status and shape are unchanged.
  • Added receivedDateFrom and receivedDateTo filters to Receipt List. Both are inclusive whole days in the shop's timezone and apply to the receipt's effective received date (the override when one is set, otherwise the recorded date). Either bound may be sent alone; a time of day is ignored. Addition-only.
  • Added unitPrice and lineItemType (part, outsideProcessing or fee) to the line items returned by Receipt List when includeReceiptLines is set. unitPrice is per Fulcrum's unit of measure, so it multiplies with convertedQuantityReceived, and is discounted where the line carries a discount. null means there is no price (a sales-order receipt, an unresolvable line, or a fee ordered without a quantity), never zero. Addition-only.
  • Corrected sorting and paging on Receipt List: the page was cut before the sort was applied, so skip/take walked an arbitrary order. The whole result is now sorted first, with id breaking ties, and an unknown sort.field falls back to orderId instead of failing.
  • Corrected Receipt List: purchaseOrderIds combined with any other filter also returned sales-order receipts, and salesOrderIds likewise returned purchase-order receipts. Only the side named is searched now; naming neither still searches both.
  • Changed qtyCompletedThisRun on Reporting Job Activity By Operator List to credit an entry to the day of the operator's timer it was logged during, so a count logged after midnight UTC stays with the shift that made it, and to keep an entry that matches no timer as a row of its own where the operator ran no timer that day, instead of omitting it. Each inventory entry counts on one operation rather than on every operation of its item. Rows can appear or move between days; shapes are unchanged.
  • Corrected shippedDateOverride on Shipment Update and Shipment Patch: it is now persisted and returned, and takes precedence over shippedDate wherever a ship date is reported. Update is a full overwrite: omitting the field or sending null clears it, so an integration that updates shipments without it clears a date set in the app. On patch, only an operation naming /shippedDateOverride changes it. Send midnight UTC (2014-10-23T00:00:00Z); the value is stored as sent and reports compare it as a date. On update, a value outside 2000-01-01 to 2099-12-31 is rejected with 400; patch does not range-check. shippedDate and shippingCost remain accepted but not applied.
  • Added a modifiedAfterUtc filter and a salesOrderModifiedUtc field to Reporting Sales Order Lines List, so a sync can pull only what changed. The bound is exclusive and compares the full date and time, not the calendar day like the endpoint's other date bounds — send back the largest salesOrderModifiedUtc you hold to get exactly what moved after it. The stamp is order-grain: any save of the order returns all its lines; job and shipment-header changes do not move it. Addition-only — existing payloads gain the field but no field changes.

9/8/2026​

  • Added shipment as an attachment owner type. Attachment List and Attachments Download accept owner / owners entries of { "type": "shipment", "id": <shipmentId> }, where <shipmentId> is the id returned by Shipment List; shipment-owned rows come back with owner.type shipment, and Attachment Get and Attachment Download return them. Create Attachment and Create Remote Attachment accept Shipment as the owner type, rejecting an unknown shipment id with a 400. On Attachment Get and Attachment Download, a user-bound token must hold View Shipments to read a shipment-owned attachment. Addition-only — existing owner types are unchanged.
  • Added customerItemNumber to the rows returned by Reporting Shipping List. It carries the customer's part number from the shipment line's source sales-order line; a line fulfilling outside processing carries null. Addition-only — existing payloads gain the field; no existing fields change.
  • Added Job Message List (POST /jobs/{jobId}/messages/list) and Job Message Create (POST /jobs/{jobId}/messages) over the job's chat. Send itemToMakeId and operationId together to address one operation's chat; one without the other is a 400. The list is paged by skip/take, fixed to createdUtc descending (a sort is a 400); a job with no chat yet returns an empty page. Create takes body and optional mentions — each must be a user id, and mentioned users are subscribed to the chat — and returns the new message id. Addition-only.
  • Added jobReferences to the purchase order, returned by Purchase Order Get, Create, Update and Patch. Each entry carries id, number and name, and reports a job once however many times the order references it. A purchase order reaches a job three ways — associated with the order itself, allocated to one of its part lines, or ordered through an outside-processing line — and only the third was previously visible, on Outside Processing Line Items List. All three are now reported together, so "which jobs is this order for" is one read rather than a walk of the line items that could only ever answer for outside processing. name falls back to the job's number when the job is unnamed, matching what the purchase order screen shows. Addition-only — existing payloads gain the field but no field changes.
  • Added jobIds to purchase order part line items, returned by Part Line Items List, Get, Update and Patch — the jobs a line's material is allocated to, at line grain rather than the order grain of jobReferences. A line with no allocation returns an empty array, never null. The allocated quantity is deliberately not reported: it is not populated on every path that creates an allocation, so a number here would read as zero against material that is genuinely allocated. Addition-only — existing payloads gain the field but no field changes.
  • Added a jobId filter to Purchase Order List, matching orders associated with that job by any of the three routes above. Answers the reverse question — what has been ordered for this job — without pulling orders and discarding most of them, and narrows the query itself rather than just the response. Combines with every existing filter. A job that no order references returns an empty list. Addition-only — existing requests are unaffected.
  • Fixed every JSON Patch endpoint failing with a server error when the request names a path the endpoint does not have — for example /materialDetails/unit on Item Patch. Such a request is now rejected with a 400 whose message names the segment that was not found, so it can be corrected from the response alone. The other ways a patch body can be malformed answer 400 the same way: an operation the endpoint does not support, and a value the target field cannot hold. A failed RFC 6902 test operation also answers 400 rather than 500 — it is a state-conflict probe rather than a malformed document, so treat that 400 as retriable after refetching the record. This covers every patch endpoint — Quote, Sales Order, Purchase Order, Invoice, the part, fee, blanket, refund, vendor-credit, and outside-processing line-item patches on sales orders, purchase orders and invoices, and the patches for items, jobs, customers, vendors, shipments, receipts and receipt line items, timers, tags, and inventory-event details. Consumers that detect these failures by matching on 500 will now see 400; patches naming valid paths are unaffected.
  • Added Nesting Nestable Jobs List — POST /nesting/nestable-jobs/list, a paged list of nestable groups: a material shape paired with the operation it is cut on, with the job operations still waiting to be nested and the work-order operations already created. Filter on needNesting, existingNests, materialForms, operationIds, materialShapeIds, earliestStartOnOrBefore and search. earliestStartOnOrBefore is a day-inclusive calendar date (YYYY-MM-DD; a valid time or offset is ignored) and drops groups with no dated job operation, so existing-nest-only groups never survive it. New endpoint — no existing behavior changes.
  • Added Work Order Operation Nesting Setup — GET /work-orders/{workOrderId}/operations/{workOrderOperationId}/nesting-setup, returning the nest planned onto one work-order operation: its parts, the sheets it cuts them from with completedCount against count, and the parts it could not place. An operation with no nest answers 200 with isNested false, machineTimeSeconds 0 and empty lists. Returns 404 if the work order does not exist or has been deleted, or has no operation with that id. New endpoint — no existing behavior changes.

9/5/2026​

  • Corrected how externalReferences entries render on read and how PATCH writes them. externalId now returns null when the record holds no value (it returned "") on customers, items, quotes, sales orders, purchase orders, inventory event details, vendors and timers. On customers and sales orders, type, displayId, status and url now return "" when the record holds an empty string (they returned null). On customers, items, quotes, sales orders and purchase orders, a PATCH now stores a blank member as "", including on an entry the request never mentioned — both previously became null. POST and PUT are unchanged: a blank member is stored as no value, and a blank externalId is still rejected as required. Invoices, receipts and shipments are unchanged. A consumer that treats null and "" alike sees no difference.

9/2/2026​

  • Changed qtyCompletedThisRun on Reporting Job Activity By Operator List to net a day's negative entries instead of dropping them, so a day can read lower than it reported, negative, or zero; unitsPerHour moves with it. The run close-out now stands in only for an operation with no non-zero entries. Deleted job-log entries no longer count here or in qtyInventoriedThisRun. A day whose entries net to zero, previously omitted, now returns a row, so totals and paging can change.
  • Changed the rows printed by Purchase Order PDF. When the tenant has line consolidation enabled in their PDFs & Emails settings, stored part lines that agree on item, unit price after discount, expected receive date, and the item's custom unit-of-measure multiplier print as a single row carrying their summed quantity, the sum of their subtotals, and each stored line's number in the # column — so the document can show fewer rows than the order holds. Two lines both without an expected receive date count as agreeing. Outside processing lines consolidate on item, price, and expected receive date; vendor credit and fee lines never merge. The order's stored lines and its totals are unchanged. The setting is off by default, so an integration on a tenant that has not enabled it sees the same document as before.

9/1/2026​

  • Changed item writes to require an inventory unit of measure. An item has always been meant to carry one, but several paths let an item reach the database without it, and downstream inventory, costing, and purchasing then had no unit to work in. Item Update, Item Patch, the item tag endpoints (POST and DELETE /items/{itemId}/tags/{tagId}, PUT /items/{itemId}/tags), and Item Add Revision now answer 400 when the item they target has no inventory unit of measure, rather than writing or cloning an item that cannot be stocked. Item Create is unchanged: unitOfMeasureName was already required there. Set the unit on the item first, through Item Update or in the app, and the call succeeds. Only items already stored without a unit are affected, so an integration whose items all carry one sees no change.
  • Changed how Create Attachment classifies an uploaded PDF. A 3D PDF — a .pdf whose bytes carry a PRC 3D-annotation stream — is now recognized as a CAD file, so it is processed for the in-house 3D viewer and receives a rendered thumbnail, the same as any other CAD upload. A plain 2D PDF is unchanged: it stays on the document path with its usual thumbnail. The distinction is drawn from the file's contents, not its extension or the request — nothing in the request selects it, and no other file type is affected. A PDF that is not a 3D PDF, and every non-PDF upload, behaves exactly as before.

8/31/2026​

  • Added unitOfMeasureName to Item Update and Item Patch, so a stocking unit picked wrongly at create time can be corrected without a trip into the app. Omitting the field — or sending null — keeps the item's current unit, the same way number and externalReferences behave; every other field on the update remains an unconditional overwrite. The unit must belong to the item's existing unit type: a Pieces item accepts Piece, Set or Case, and anything else is a 400 naming the item's unit type and the units it will accept. The unit type itself stays create-only, here and in the app — an item created under the wrong unit type has to be recreated. A change is only accepted while nothing still depends on the current unit, because nothing is converted when it changes: on-hand quantities are stored as bare numbers, a sales unit of measure conversion is a ratio against the current unit, and a price break that names an amount — item, vendor, customer, or customer-tier — is a price against a unit of the item's. A break holding only a margin or a markup is a percentage, so it survives the change and does not block it; creating an item seeds exactly one of those from the shop's default margin, which is why a freshly created item can still be corrected. So a change is rejected with a 400 when the item is in use by a quote, sales order, purchase order, job, invoice or another item's routing; when it holds inventory on hand; when the request sends sales unit of measure conversions alongside the change; or when any of its price breaks carries a price. Each 400 names which of those blocked it. Past inventory transactions are not checked and are not converted: an item whose on-hand has returned to zero may change its unit — the same as correcting it in the app — and its earlier transaction rows are then read in the new unit. Clear the blocker in one request, then change the unit in a second — each condition is read as the item stands before the update, so doing both at once is still rejected. The one exception is salesUnitOfMeasureConversions: because an update replaces them wholesale, a request that changes the unit and sends none is accepted and leaves none behind, while a request that changes the unit while conversions are present — sent on the update, or carried forward from the item by a patch — is rejected. An item with no unit type recorded is also rejected, and its unit cannot be corrected through this endpoint at all. Sending the unit the item already has is not treated as a change, so a read-modify-write integration that echoes the field back keeps working on items in any of those states.
  • Changed nextCalibrationDateUtc on Tool List and Tool Get: a tool that is inactive with reason retired or lost now returns null — it is permanently out of service, so nothing is ever due against it, the same as a tool with calibrationFrequency none. Other inactive reasons still return the computed date. lastCalibrationDateUtc and the tool's calibration records are unchanged, and clearing the reason restores the date. Consumers deriving due lists from this field will see retired/lost tools drop out; request and response shapes are unchanged.

8/28/2026​

  • Added a salesOrderNumbers filter to Reporting Sales Order Lines List, matching lines by the sales-order number shown in the product. A consumer tracking a known set of orders can ask for exactly those orders in one call instead of pulling a broad date or status slice and discarding most of it — which also narrows the query itself, not just the response. Accepts up to 500 numbers, matched exactly; duplicates are ignored, and sending an empty list (or omitting the field) returns unfiltered results as before. A longer list is rejected rather than trimmed, so a request can never quietly match fewer orders than it asked for. Combines with every existing filter. Addition-only — existing requests are unaffected.
  • Corrected the published response for Sales Order PDF — GET /sales-orders/{salesOrderId}/pdf now declares its 200 as application/pdf binary content in the OpenAPI schema, matching Purchase Order PDF. Generated clients that previously typed the response as empty will now type it as a binary download. The bytes on the wire are unchanged.
  • Added Sales Order PDF — GET /sales-orders/{salesOrderId}/pdf, returning application/pdf as SalesOrder_{number}.pdf. The PDF reflects the order's current state and the tenant's PDFs & Emails settings at the time of the request; it is not a previously generated or emailed copy. Requires View Sales Order permission. Returns 404 if the sales order does not exist or has been soft-deleted — unlike the in-app preview, which still renders a deleted order. New endpoint — no existing behavior changes.
  • Added Invoice PDF — GET /invoices/{invoiceId}/pdf, returning application/pdf as INV{number}.pdf. The PDF reflects the invoice's current state and the tenant's PDFs & Emails settings at the time of the request; it is not a previously generated or emailed copy. Date formatting is presentational and may vary by environment. Requires View Invoices permission. Returns 404 if the invoice does not exist or has been soft-deleted. New endpoint — no existing behavior changes.
  • Added Shipment PDF — GET /shipments/{shipmentId}/pdf, returning the shipment's packing slip as application/pdf. The file name is based on the order fulfilled by the shipment and the shipment's sequence number, rather than the requested shipment ID. For example, SO1862-2.pdf for a shipment fulfilling a sales order and PO104-1.pdf for outside processing. The PDF is available in every status, including for shipments that have been cancelled. Requires View Shipments permission. Returns 404 if the shipment or the order it fulfils does not exist or has been deleted. New endpoint — no existing behavior changes.

8/27/2026​

  • Changed qtyCompletedThisRun on Reporting Job Activity By Operator List to report what each operator reported, rather than the operation's run total. Completing an operation records that total against whoever closed it, and it previously replaced that operator's own reported quantity — on a run finished by one of several operators, the whole run was credited to the closer. Where anyone reported quantity on an operation, each operator is now credited only with what they reported; a close-out still stands in where nobody reported individually and it is the sole record. Per-operator quantities on such an operation fall, and need not sum to unitsCompletedOnOperation. unitsPerHour is derived from this field and moves with it. Request and response shapes are unchanged.

8/26/2026​

  • Added Purchase Order PDF — GET /purchase-orders/{purchaseOrderId}/pdf, returning application/pdf. The file name is based on the tenant's purchase-order title template, with Purchase Order abbreviated to PO and spaces removed. For example, the default template produces PO104.pdf for an ordered purchase order and RFQ104.pdf while it is still a draft. The same purchase order may therefore have a different file name as its status changes. Requires View Purchase Order permission. Returns 404 if the purchase order does not exist or has been soft-deleted. New endpoint — no existing behavior changes.

8/25/2026​

  • Changed quantityShipped on Shipment Line Items List to report what a line actually shipped: its packed quantity once the parent shipment has shipped, and 0 before then. It previously derived from the line's packingStatus, which is a separate value an operator can pin by hand and which shipping does not clear — so a shipped line whose packing status read NotPacked reported 0 even though its packed quantity went out and was invoiced, while a line packed on a shipment that had not yet shipped reported that quantity as already shipped. Consumers summing this field will see shipped totals rise where the first case applied and fall where the second did. quantityPacked, packingStatus, and shipmentStatus are unchanged, and the field now agrees with the shipped quantity reported by Reporting Shipping List.
  • Added salesOrderLinePrimaryKey to Reporting Sales Order Lines List rows — an opaque identifier unique to each row, stable within and across pages, for joining rows back to a line. The line-item number is not unique. Addition-only — existing payloads gain the field but no field changes.

8/24/2026​

  • Added dropship and dropshipCustomerPoNumber to the sales order. Returned by Sales Order Get and Sales Order List, and accepted by Sales Order Create, Update, and Patch. dropship marks the order as fulfilled by shipping directly to the end customer — the same flag as the in-app Dropship toggle on the deliverables timeline — and dropshipCustomerPoNumber carries the end customer's purchase order number, which prints on dropship paperwork and labels. On create, dropship defaults to false when omitted. On update the two fields move together and are written only when dropship is supplied: omit dropship and neither field changes, so an existing integration that keeps PUTting its current payload never turns dropshipping off and never clears a PO number authored in the app. Sending dropship with no dropshipCustomerPoNumber clears the PO number — that is the only way to clear it, since a blank string is coerced to null before validation rather than acting as a clear-this-field sentinel. Note the asymmetry: dropshipCustomerPoNumber does not follow the replace-on-PUT behavior of customerPoNumber and publicNote, which are cleared by omission. Addition-only — existing payloads gain both fields but no field changes.

8/23/2026​

  • Added isLotTracked and isNonInventory to Item Update, and isNonInventory to Item Create. Both values were already returned by item reads, and isLotTracked was already settable at create time, so until now neither could be corrected on an existing item. Like number, both are opt-in on update: omitting a field (or sending null) keeps the item's current value, so an update that does not mention them cannot change them, and a value that matches the item's current one changes nothing. isNonInventory also keeps the item's inventoried state in step, since a non-inventory item is never held in inventory. Only a buy item that is not sellable can be non-inventory. On create, anything else is rejected with a 400. On update the same 400 applies to turning it on, while an item that is already non-inventory can restate that value — so a read-modify-write update of a legacy item that is already in that state does not start failing. Addition-only: requests that omit the new fields behave exactly as before.
  • Added Item Material Create — POST items/material — for creating an item from a material shape. This is how a material item's thickness, form and length unit become settable through the API: they are not request fields, they come from the shape selected, along with the density used to calculate the item's weight, so pick the shape carrying the combination you want. The request names the shape (materialShapeId) and only the dimensions that vary: length for every shape, plus width for planar shapes (sheet, plate, tread plate). A planar shape sent without width, or a linear shape (bar, tube, pipe, beam, angle, channel) sent with one, is rejected with a 400 rather than defaulted or ignored. Items are created as Buy items measured in Pieces and take the shop's default buy-item accounting code, except a remnant (isRemnant true), which is created with none. The shape must already be activated for the shop: an id that exists only in the materials database returns a 404 pointing at Material Activate, which this endpoint deliberately does not call for you because activating a shape also un-archives every existing non-remnant item that uses it. Worth planning for: a material item's number is derived from the shape and dimensions rather than supplied, so posting the same shape and dimensions twice returns the id of the item that already exists, un-archiving it if it was archived, instead of creating a duplicate. The number does not encode remnant state, so isRemnant applies only when a new item is created and is ignored on that collision — the item you get back keeps the remnant state it already had. materialDetails on the item read and update endpoints is unchanged and stays read-only.

8/21/2026​

  • Added a shipped-date window to Reporting Shipping List: shippedDateFrom / shippedDateTo, bounding the date a shipment actually shipped — its ship-date override when set, else its recorded ship date. Distinct from the existing shipByDate bounds, which filter the date it was due to ship. Both bounds are day-inclusive, covering the whole to day whatever time a shipment went out, and match only shipments whose status is Shipped — an override can be set while a shipment is still open. Addition-only — existing requests are unaffected.

8/20/2026​

  • Added shipped-date and invoiced-date windows to Reporting Sales Order Lines List: shippedDateFrom / shippedDateTo, invoicedDateFrom / invoicedDateTo, and the dates they filter on — firstShippedDate, lastShippedDate, firstInvoicedDate, lastInvoicedDate — on every row. A line ships and is invoiced in tranches, so a bound pair selects lines whose activity span overlaps the window rather than only those wholly inside it; a line with no such activity carries nulls and is excluded by any bound on it. Bounds are day-inclusive. Addition-only — existing payloads gain the fields but no field changes.
  • Changed paging on Reporting Sales Order Lines List to a total order. Lines tying on every sort key — same ordered date, order number, line item, and unit price — previously ordered arbitrarily, so one could repeat on the next page or be skipped altogether. A unique line key now breaks those ties. Filters and row shapes are unchanged, but a caller paging the same query may see tied lines fall on different pages than before.

8/19/2026​

  • Added requiredQuantityLbs, collectedQuantityLbs, and outstandingQuantityLbs to Material Requirements Report rows — the existing kilogram quantities converted to pounds. Populated wherever requiredUnitOfMeasure is kg — always the case for material requirements, and also for an item requirement whose item is stocked by weight; null for quantities in any other unit, where a weight conversion would be meaningless, and null wherever the kilogram value is itself null (an unresolved nest weight stays unknown rather than becoming zero). The kilogram fields are unchanged. Addition-only.
  • Added Item Purchase History — returns every purchase of one item within a date window, newest first. Each entry carries the purchase order, vendor, ordered unit price, billed unit price, effectiveUnitPrice (the billed price when present, otherwise the ordered price), and quantities ordered and received. Includes a summary with min/max/average price, last price paid, last order date, and distinct vendor count. Counts only orders with status Ordered or Paid. months defaults to 12 and is clamped to 1–60. Not paginated — bounded by one item and the window.
  • Documented itemOrigin on Item Create. Use buy, make, makeOrBuy or customerSupplied; the schema also carries kit and none for historical reasons, and while both are accepted neither is supported for new items. No behavior change — the field has always accepted every value in its schema. To spell out the one that was hardest to discover: a customer-supplied item is created by sending itemOrigin: "customerSupplied". itemOrigin remains create-only, so an existing item's origin cannot be changed through the API — an item created with the wrong origin has to be replaced rather than converted.

8/18/2026​

  • Added reason to Scrap Report entries — a reference (id, name) to the reason selected when the scrap was recorded, or null when the entry carries none. The reason has always been captured with the entry and shown in the product; the report endpoint now returns it, so a consumer grouping scrap by cause no longer needs the Excel download. Addition-only — existing payloads gain the field but no field changes.
  • Fixed Item List failing with a server error whenever the descriptionFilter filter was supplied — the filter now runs in the database. An item matches when its description contains the supplied text, compared case-insensitively, and the filter narrows results alongside any other filter sent with it. Separately, the documented syntax for this field was wrong on both v1 and v2: it described quoted phrases for exact matching and a leading - to exclude a term, neither of which is implemented — v2 has matched on a plain case-insensitive substring since it was repaired, and v1 now does the same. Both field descriptions have been corrected; no v2 behavior changes.
  • Changed the due-window filters on Tool List: isOverdue, dueWithin7Days, and dueWithin30Days no longer match out-of-service tools — tools that are inactive with any reason other than OutForCalibration: Lost, Damaged, RequiresRepair, Retired, or a legacy row with no recorded reason. Such a tool no longer needs calibration, so it no longer counts as due or overdue. A tool that is inactive with reason OutForCalibration still matches, because it is inactive only while it is being calibrated. This matches the in-app Calibration Overdue / Due 7 Days / Due 30 Days KPIs, which now exclude the same tools. Request and response shapes are unchanged — only the filtered row set changes.

8/17/2026​

  • Added measurementRangeMinPrecision and measurementRangeMaxPrecision to tools — the number of decimal places each measurement-range bound was entered with, matching the existing accuracyPrecision. A range entered as 0.1000–0.4000 now keeps its trailing zeros on the tool and on generated calibration certificates instead of collapsing to 0.1–0.4. Returned by Tool Get (and echoed by the create/update responses), and accepted by Tool Create and Tool Update. Omitted or null means no precision was recorded, and the values render at their natural precision as before. Addition-only — existing payloads gain the fields but no field changes.

8/14/2026​

  • Added progress-billing line items to invoice reads: Invoice Get and Invoice List now return two new line-item type values, ProgressBilling (an installment invoice's percentage-of-order charge) and ProgressBillingAdjustment (the final invoice's reversal of one already-billed installment). Both carry quantity 1, the line's amount in price and discountedPrice, the line's accounting code, and isTaxable false. Addition-only for existing consumers: these lines exist only on invoices generated from a progress-billing schedule, and invoices without one are unchanged.
  • Added needsQualityPlan to item reads — a boolean indicating whether the item requires an approved quality plan. Combined with the existing qualityPlanStatus, a consumer can distinguish an item that has an approved plan (needsQualityPlan true and qualityPlanStatus Approved) from one that needs no plan at all (needsQualityPlan false), which the status alone could not express. Returned by Item Get, Item List (including its v2), Item Update, and Item Patch. Read-only — returned on these reads and mutation responses but not settable on create/update. Addition-only — existing payloads gain the field but no field changes.

8/12/2026​

  • Added a names filter to Shipment List, matching shipments by the shipment number shown in the product (e.g. SHP-SO1234-1, SHP-PO5678-2). Resolving a shipment from a number previously meant looking up the parent sales or purchase order and walking its shipments; a number now resolves in a single call. Accepts up to 500 names, matched exactly and case-insensitively; sending an empty list (or omitting the field) returns unfiltered results as before. Addition-only — existing requests are unaffected.

8/11/2026​

  • Fixed Receipt List failing with a server error whenever the externalReference filter was supplied — the filter now runs in the database, for both purchase-order and sales-order receipts. Filter semantics are unchanged: a receipt matches when it carries the named external-reference key and, where type or externalId are also supplied, that same entry matches them.
  • Fixed Item List failing with a server error whenever the customField filter was supplied — the filter now runs in the database. An item matches when one of its custom fields is exactly the requested key:value pair, compared case-insensitively; partial key or value fragments do not match.

8/10/2026​

  • Added onFair to the full-routing in-process-tracking endpoints — get, list, and create for jobs, quotes, and sales-order part line items. It marks a checkpoint as reported on the First Article Inspection Report (FAIR), a meaning that until now was carried by firstArticle. The two are independent from here on: firstArticle remains the sampling instruction (it still resolves an unsupplied frequency to 0), while onFair governs FAIR membership only and never affects sampling. onFair defaults to false on create, so an integration that wants a checkpoint reported on the FAIR must set it explicitly — firstArticle: true on its own no longer implies FAIR membership. Reads are addition-only: existing payloads gain the field but no field changes.

8/7/2026​

  • Fixed Time Clock List failing with a server error whenever startedDateRange or stoppedDateRange was supplied — the range filters now run in the database. Filter semantics are unchanged: a still-running entry (no stop time) is treated as unbounded, so it matches any stoppedDateRange.start and is excluded by any stoppedDateRange.end.

8/6/2026​

  • Fixed Purchase Order Get and List returning a spurious contactId for purchase orders that have no contact — the field now reads null for contactless purchase orders, and the schema declares it nullable. Purchase orders with a real contact are unaffected; consumers that assumed the field always holds a value should treat it as optional.
  • Fixed Purchase Order Outside Processing Line Item Create failing with a server error when the targeted job operation carried no item reference or no linked system operation — the line item is now created from the fields that are present, and outside-processing line-item reads return itemId as null (now declared nullable) for such lines. Requests naming complete job operations are unaffected.
  • Added Job In-Process Tracking Response List — lists a job's in-process tracking checkpoints together with every recorded operator reading (stable reading id, numeric/boolean/text value, the operator plus separate recordedBy/updatedBy attribution, the measurement tool, and timestamps), optionally filtered by phase. Each checkpoint also reports its drawing and recording units and the requirement expressed in both (targetValue/minimumValue/maximumValue are in drawing units; recordingTargetValue/recordingMinimumValue/recordingMaximumValue and the readings are in recording units). measurementToolNextCalibrationUtc is the tool's current next-calibration date (live, not snapshotted at reading time). Previously only checkpoint definitions were exposed (via the routing endpoints); this returns the readings actually captured during production. The result is intentionally single-job-bounded and is not paginated — the readings axis is not independently bounded — and an unknown job id returns 404.
  • Fixed Sales Order Refund Line Item Create and Update mishandling the order's receiving record when adding or removing a return: on some orders a refund-with-return failed with a server error (a dangling receiving reference), and on others the order's receiving record was silently replaced — detaching previously recorded receipts from the order. Both endpoints now load and mutate the order's existing receiving record. Request and response shapes are unchanged.

8/5/2026​

  • Fixed Note Get failing with a server error for every request — the endpoint's channel lookup sat on an unimplemented legacy query path, so no call could ever succeed. It now behaves as documented: 200 with the note for a valid id, 404 when no note has that id. Request and response shapes are unchanged.

8/3/2026​

  • Changed Quote Status Update: transitioning a quote to Sent now stamps its quotedDate with the send time, and — only when the quote's expiration still sits at its create-time default (the configured quote-expiration window measured from the quoted date) — recomputes expiration from the newly stamped date. An expiration that was set deliberately is never moved. Marking an already-Sent/Won/Lost quote Sent remains a no-op and changes neither field. Integrations that write a historical quotedDate and then mark the quote Sent should reverse the order — set the status first, then write the dates (both fields remain writable afterward).
  • Added isMaterialLine to routing input item reads — true when the line is tied to an input material (created by a material selection) rather than being a plain component line. Returned by Item Routing Input Item List, Item Routing Input Item Get, the operation-item reads, and the job, quote, and sales-order full-routing input item endpoints. Addition-only — existing payloads gain the field but no field changes.
  • Fixed Item Routing Operation Batch leaving input materials and input items associated with operations the batch had removed. Steps omitted from the request now release those associations (routingStepId returns to null), matching single-operation deletion. The endpoint also returns a 400 naming the id when a well-formed systemOperationId matches no operation in system data, where it previously failed with a 500.

7/31/2026​

  • Improved the rejection for picking material held for incoming inspection via Job Operation Pick. Picking a lot reserved for an incoming or failed inspection has never been allowed; previously a pick naming such a lot by id failed with the generic "No inventory for the given item, location, and lot." Requests now fail with the descriptive rejection naming the lot and the hold (e.g. Lot {number} is being held for incoming inspection and cannot be picked.), matching the in-app behavior. Still a 400; only the message is more specific — consumers should match on status, not message text.
  • Inventory Override now rejects an override that would reduce the on-hand quantity of a lot held for incoming inspection (or one that failed inspection), with a 400 naming the lot and the hold — quarantined material can only leave inventory through the inspection workflow (release, or rollback of the receipt). Overrides that keep or increase the held quantity are unaffected, as are all overrides on unreserved and job/sales-order-reserved lots.

7/30/2026​

  • Fixed price on sales order discount line items reading as 0. The calculated discount amount (and the derived subTotal/preDiscountSubTotal/discountedPrice on the generic line-item shape, plus absoluteAmount on the discount line item) is now computed from the sales order, so percentage and absolute discounts return their real value for every sales order. Percentage discounts are calculated over the order's part and blanket lines, matching the sales order total. Affects the Sales Order Discount Line Item and Sales Order Line Item endpoints.

7/29/2026​

  • Added accountingHeldUtc to Receipt List and Receipt Get responses. The field is set while a receipt's accounting is deferred because it contains material held for incoming inspection (tenants using the new after-inspection invoice-timing mode) and is null otherwise — including for every receipt on tenants that keep the default on-receipt mode, where nothing changes. While a receipt is held, Receipt List excludes it; it appears (with accountingHeldUtc null) once its inspections complete. Receipt numbers are stable across the hold — a held receipt keeps occupying its position, so siblings' numbers never shift when it is released. Receipt Get by id remains unfiltered and returns held receipts with the field set. Consumers that reconcile bills from the receipt list should treat a held receipt exactly like one that hasn't been received yet: it will surface in the list when it becomes billable.

7/28/2026​

  • Added ten values to the tool type enum: CmmDatumSphere, ThreadMicrometer, InsideMicrometer, PinMicrometer, SetPlug, NptRingGage, NptPlugGage, GrooveMicrometer, WeldingEquipment, and SurfaceTesterMaster. Returned by Tool Get, Tool List, and tool calibration reads, and accepted by Tool Create, Tool Update, and the Tool List types filter. Addition-only, but consumers that map the enum should tolerate the new values.
  • Fixed Item Routing Input Item Delete and Item Routing Input Item Update not applying to the copy of the input item carried on its routing operation. Delete removed only the routing-level line, so the item still appeared on the operation (and in the UI) after a 200; update left the operation copy with stale values. Both endpoints now apply to the operation copy when it can be identified unambiguously — by shared id, or by material for lines stored with a separate id (such as those added through Item Routing Operation Item Create) when the line is the routing's only line for that material. Deleting a line that aggregates one material across several operations removes all of its operation copies; updating such a line changes only the routing-level quantity, leaving the per-operation split intact. No request or response shape changes.
  • Added expirationUtc to Auth Validate — the UTC instant at which the calling token stops being accepted, so an integration can read its own key's remaining life instead of tracking it out of band. Always a future instant, since an expired token is rejected before it reaches the endpoint. A token created with no expiry reports the maximum representable date rather than a real one. Addition-only — existing payloads gain the field but no field changes.
  • Added optional skip and take query parameters to Item Routing Input Material List. Addition-only — requests that omit them keep receiving the full list, unchanged.
  • Added requiredStockPieces to Reporting Material Requirements List — the stock pieces (nests) needed to produce the row's jobPlannedQty, alongside the existing required weight. Null on item requirement rows, and null when the material's nest yield is unknown, so null means not known rather than none needed. The value is fractional, since the unconsumed part of a piece returns to stock as a remnant — round up when sizing a purchase or a pick. Each row is scoped to one operation, so do not sum the field across a job's operations. Addition-only — existing payloads gain the field but no field changes.
  • Fixed price on purchase order discount line items reading as 0. The calculated discount amount (and the derived subTotal/preDiscountSubTotal/discountedPrice on the generic line-item shape) is now computed from the purchase order, so percentage and absolute discounts return their real value for both new and historical purchase orders. Percentage discounts are calculated over the order's part and outside-processing lines, matching the purchase order total. Affects the Purchase Order Discount Line Item and Purchase Order Line Item endpoints.

7/27/2026​

  • Added employeeId to User List results. User Get has returned the field since it was introduced, but the search response omitted it, so resolving an employee identifier for a set of users meant following every search with a per-user get. Addition-only — existing consumers are unaffected, and users with no employee identifier return null as they do on User Get.

7/24/2026​

  • Added optional includeDeleted to User List. When true, inactive/deleted users matching the search are returned (with deleted: true); omitting it (or sending false, the default) preserves the current active-only behavior. Previously a deactivated user was excluded from search results even when queried explicitly by email — inconsistent with User Get, which already returns deleted users. Addition-only — existing consumers are unaffected.
  • Added the tool calibration write surface (no sign endpoint — signing a calibration record remains a human act performed in the product — and no delete endpoints). Tool Calibration Create records a calibration: an external vendor or customer attestation, or an in-house calibration with per-checkpoint responses measured against the tool's current template. The server derives the As-Found/final results from the measurements and rejects a result that disagrees, pins the template version, stamps the measurer, and attributes customer-source records to the tool's owning customer; reference gages take no records. A save recording a new failure automatically opens an NCR, echoed as createdNcr. Tool Calibration Update edits an unsigned record (signed records are immutable) as a full replacement with re-derivation, guarded by optimistic concurrency: reads of a record by id now return an opaque version token, the update requires it, and a stale token is rejected with 409. Tool Create and Tool Update manage tools (identity, type, status, calibration schedule, ownership); a calibration frequency of none creates a reference gage, and outForRecalibrationDateUtc (also added to Tool Get) marks a tool out for recalibration in tandem with the outForCalibration inactive reason. Tool Calibration Template Create publishes a new append-only template version (checkpoints, tolerances, trials, environment ranges, master gauges); existing records stay pinned to the version they were measured against. Record writes require the Perform Calibration permission; tool and template writes require Edit Tool Template — mirroring the in-app permission model. Creates are not idempotent: a request retried after a timeout creates a second record (and a second NCR for a failing calibration) — list before re-creating.
  • Added Job Operation Complete, completing a job operation the way the shop floor does: closes any open timers on the operation, records an optional final quantity and scrap, marks the operation complete, and readies downstream operations. When the completed operation is the item's last (or a split operation producing finished goods), goods are received into inventory (with optional location, lot number, and expiration; set addItemsToInventory to false to skip) and the item — and the job, once every item is done — is completed. Complements Add Quantity Completed, which records production without completing; quantity passed to complete is added on top of previously recorded quantity.

7/23/2026​

  • Added a read-only rates block to Operation Get, Operation List, and Operation Update responses, carrying the operation's hourly cost rates (setup, labor, overhead, machine) and hourly shop rates (setup, run, machine) in the shop's primary currency. A null rate inside the block means no operation-level rate is set and the work-center rates apply. Addition-only — existing payloads gain the new block but no field changes.
  • Added the tool calibration read surface. Tools: Tool Get returns a tool's identity (number, rendered T-{number} for display), serial number, type, status, calibration schedule, computed nextCalibrationDateUtc, and its latest calibration outcome (lastCalibrationResult, lastCalibratedBy); Tool List additionally returns the derived calibrationStatus the tools grid displays, with filters for search, types, statuses, due windows (isOverdue, dueWithin7Days, dueWithin30Days), reference gages, and modifiedAfterUtc for incremental polling of created/edited tools. Templates: Tool Calibration Template Latest, Versions List, and Version Get expose the checkpoints, tolerances, trial counts, environment ranges, and master gauges a calibration is measured against, plus each version's effective range. Records: Tool Calibration Get and Tool Calibration List return calibration history — results, As-Found/As-Left measurements by checkpoint and trial, the pinned template version, and sign state — filtered by tool, vendor, result, type, and date range. Tool Calibration Certificate downloads a record's certificate PDF (the exact artifact frozen at signing once a record is signed). All endpoints require the View Tool Calibration permission on user-bound tokens.

7/22/2026​

  • Added optional number to Item Update to support renaming items. Omitting the field (or sending null) keeps the current number. A rename enforces number uniqueness (400 on collision) and updates every reference to the item — BOM inputs, usage, purchase orders, and the system lot. Uniqueness is scoped to number + revision, so when renaming an item with multiple revisions, rename every revision of the family.

7/20/2026​

  • Added routingStepId to routing input items, identifying the operation a required item is attached to. Returned by the input-item read endpoints, including Item Routing Operation Items List, Item Routing Input Items List, and Job Full Routing Input Items List. Addition-only — existing payloads are unaffected.
  • Added Reporting Material Requirements List endpoint returning per-operation required items and materials for scheduled jobs, with resolved required quantities (items in their unit of measure, materials as a weight in kilograms) plus collected and outstanding amounts. Lets consumers report material demand across scheduled operations in a single paged call instead of fanning out per job to routings, items-to-make, and operations.
  • Added workOrderId, workOrderName, workOrderOperationId, and workOrderOperationName to the timer response for List Job Tracking Timers and List Timers. Timers tracked against a work order now surface the work order and its operation names, which were previously populated only for job-tracked timers. This is an addition-only change — existing consumers are unaffected.

7/19/2026​

  • Fixed price on invoice discount line items reading as 0. The calculated discount amount (and the derived subtotal/discountedSubtotal on the generic line-item shape) is now computed from the invoice, so percentage and absolute discounts return their real value for both new and historical invoices. Affects the Invoice discount line item and line item endpoints.

7/16/2026​

7/15/2026​

  • Sales-order date fields (orderedDate, dueDate, productionDueDate, deliveryDueDate, and part-line-item deliveryDate) now use the calendar date exactly as written, ignoring any time-of-day and UTC offset in the supplied value. Previously an offset-bearing timestamp could roll the stored date to an adjacent day. Affects Sales Order Create, Update, and Patch, plus Sales Order Part Line Item Create, Update, and Patch. Consumers sending date-only values or midnight-UTC timestamps see no change.

7/14/2026​

  • Added Timer Create endpoint for recording completed setup, labor, and machine timer blocks with explicit startedOnUtc and stoppedOnUtc timestamps — for time captured outside Fulcrum (backdated up to 30 days).
  • Removed the incorrect minLength: 1 published on optional description fields across item, quote, sales-order, purchase-order, and invoice schemas. The server has always accepted empty descriptions; the published schema now agrees, so schema-validating clients no longer reject them.

7/13/2026​

  • Operation Get and Operation List now tolerate operations stored with a time option but no time unit, returning null time blocks for them instead of failing the whole request.

7/10/2026​

  • Added Shipment Get endpoint.
  • Added shipByDateBefore, shipByDateAfter, shippedDateBefore, and shippedDateAfter filters to Shipment List.
  • Added salesOrderId and purchaseOrderId filters to Shipment Line Items List; the line-item response now also carries shipmentStatus, shipByDate, shippedDate, and shippedDateOverride from the parent shipment.
  • Added calculated shipByDate to Sales Order Get, List, and Update responses — the earliest ship-by date across the order's non-cancelled shipments, falling back to the earliest delivery due date minus the customer's shipping lead time.
  • Added modifiedAfterUtc and modifiedBeforeUtc filters to Job List and Operation List for incremental polling of changed records.

7/9/2026​

7/8/2026​

6/30/2026​

6/29/2026​

  • Fixed Job Tracking Get failing for jobs whose cost breakdowns contain legacy overhead rows; the cost-breakdown costType value set gained overhead and unknown. Also fixed componentLabor cost-breakdown lines reporting the material per-unit cost instead of the labor per-unit cost.

6/24/2026​

6/18/2026​

6/15/2026​

  • Fixed Inventory Event List failing whenever the types, secondaryTypes, sourceTypes, or reservedForTypes filters were supplied.

6/8/2026​

  • Added rework information to Job Operation List: isRework and hasAssociatedRework flags, plus a rework object with the reason, notes, quantities, and creator.

5/26/2026​

  • Corrected error status codes across the API: requests referencing records that don't exist now return HTTP 404, and business-rule validation failures return HTTP 400 with the reason in the response body — many of these cases previously returned HTTP 500.

5/25/2026​

5/20/2026​

  • Added box to the packingDetails entries on Shipment Line Items List, identifying the box a packed quantity was packed into.

5/8/2026​

  • Added CAPA Get endpoint.
  • Added NCR Get endpoint.
  • Added Scrap Report endpoint returning scrap entries (item, quantity, value, operator, operation, work center, department, equipment, and job) over a date range.

5/6/2026​

  • Added Item Customer endpoints for managing customer-specific item data — customer item number and name, with read-only customer price breaks: Create, Update, List, and Delete.

5/4/2026​

5/3/2026​

4/23/2026​

4/12/2026​

4/10/2026​

4/6/2026​

3/24/2026​

  • Fixed Item Routing Operation Batch to apply inputMaterialIds association and validation to existing routing steps, not just newly created ones.

3/5/2026​

3/2/2026​

2/24/2026​

  • Added createdFromQuoteId to Sales Order Get and Sales Order List so consumers can resolve a sales order's originating quote without scanning the full quote list.

2/21/2026​

  • Removed operation references from cost-breakdown lines and timers. Cost breakdown lines now expose a flat referenceId and referenceName instead of a nested operation object. Affects all endpoints that return Cost Breakdown data.

2/18/2026​

  • Purchase Order Part Line Item Patch now bypasses status validation when only externalReferences, promiseDate, or receiveByDate are being modified, matching the existing behavior on the parent purchase order.

2/13/2026​

  • Added back public API mapping for material grid query parameters on Material List.

2/12/2026​

  • Dereferenced item and location on Inventory Transactions List. The transaction response now exposes the related item and location identifiers directly instead of through a nested reference object.

2/10/2026​

  • Removed the modifications field from MaterialShapeDto (affects Material List and Material Get). The field has been unpopulated since the v3 material schema rolled out; use type, spec, subspec, and finish instead.

2/9/2026​

  • Added discountAmount (calculated total) to discount line items on invoices, sales orders, and purchase orders. Affects Invoice, Sales Order, and Purchase Order endpoints that surface discount lines.
  • Added enableRemnantSync to Item Get and Item List so ProNest integrations can opt items in or out of remnant sync.

2/4/2026​

2/3/2026​

2/2/2026​

1/26/2026​

  • Reshaped the NCR DTO: split impact information into a dedicated impact object, expanded department into a full ReferenceDto with id, and added user-reference mappings. Existing fields remain available; consumers reading impact* fields directly should migrate to the nested impact object.

1/23/2026​

  • Item Create no longer forces lotTrackingUsage to false when omitted; system settings are used for the default instead.

1/22/2026​

1/19/2026​

1/15/2026​

1/2/2026​

  • Added attachMaterialsToOperations toggle to Operation Create for Paperless Parts integrations that need to attach nestable materials to operations on creation.
  • Fixed quantity validation on invoice line item refunds — zero quantities now reject up front. Affects Invoice Line Item endpoints.

12/18/2025​

12/15/2025​

  • Replaced outsideProcessingTime with outsideProcessingCost on operation DTOs returned and accepted by Operation Create, Operation Get, and the operation entries inside item-routing endpoints. Consumers using outsideProcessingTime for outside-processing operations must migrate.

12/12/2025​

  • Added unit specifiers (widthUnit, heightUnit, lengthUnit, thicknessUnit) to Material Activate so metric and imperial materials can be created without ambiguity.

12/2/2025​

11/26/2025​

11/19/2025​

11/12/2025​

11/6/2025​

10/24/2025​

  • Restructured Item-Vendor List to return the full vendor resource (including price-break information) rather than the base item shape only.

10/21/2025​

10/20/2025​

10/17/2025​

10/15/2025​

10/9/2025​

  • Job Create now routes sales-order-based job creation through the full sales-order job-creation pipeline so all ancillary data is gathered correctly when supplying salesOrderId and salesOrderLineItemId.

10/8/2025​

10/1/2025​

  • Added Certification Attachment Create endpoint for uploading certifications against receiving line items and items.
  • Tightened Attachment Create and Remote Attachment Create to always treat attachments as Standard. The attachmentType field has been removed from the request — use the new certification endpoint for certification uploads. The accepted owner-type set has also been narrowed (e.g. InventoryLot is now reserved to certifications).

9/24/2025​

9/23/2025​

9/19/2025​

9/17/2025​

  • Added sentDate to Sales Order Get (null until the order moves past Approved).

9/12/2025​

5/25/2025​

5/21/2025​

  • Added option to search by modifiedAfterUtc on Customer List.
  • Added option to search by modifiedAfterUtc on Quote List.
  • Added accountingDetails to all line item and item endpoints. This currently only contains the classId with planned further expansion.
  • Add Item Class List endpoint for searching item class definitions.
  • Add Item Class Get endpoint.

5/14/2025​

5/6/2025​

4/18/2025​

4/8/2025​

3/27/2025​

3/17/2025​

2/26/2025​

  • Added vendorNote information to multiple endpoints.

2/21/2025​

1/16/2025​

  • Added option to search by email on Customer List.
  • Added time basis values on operations.

1/3/2025​

12/17/2024​

12/10/2024​

11/26/2024​

  • Expand parameters for Items List to allow for case-sensitivity toggling.

11/19/2024​

  • Add NCR List endpoint.
  • Enforce line-item based endpoints to retain sort order based on their position.
  • Update line-item based endpoints to use the parent item's description if no value is supplied when the line item is created.

11/12/2024​

  • Add "yard" as valid line item unit of measure. Affects multiple endpoints that utilize units of measure.

11/05/2024​

  • Allow up to 2000 characters on Item Descriptions. Affects multiple endpoints that use this validation attribute.

10/29/2024​

10/22/2024​

10/08/2024​

10/01/2024​

9/17/2024​

9/10/2024​

  • Added workOrderOperation as an Attachment ownerType
  • Added V3 Shipments endpoint for creating, updating, and searching V3 Shipments

9/3/2024​

8/27/2024​

8/13/2024​

  • Add subtotal, and preDiscountSubTotal to partLineItems for Quotes, Sales Orders, and Purchase Orders

8/6/2024​

7/30/2024​

  • Add description, minimumProductionQuantity, minimumStockOnHand to Item Create
  • Add description, minimumProductionQuantity, minimumStockOnHand to Item Update

7/23/2024​

7/16/2024​

7/9/2024​

6/25/2024​

6/18/2024​

  • Added Equipment List for retrieving a list of equipment.
  • Added Equipment Get for retrieving a piece of equipment.
  • Added Department List for retrieving a list of departments.
  • Added Department Get for retrieving a department.
  • Added WorkCenter List for retrieving a list of workcenters.
  • Added WorkCenter Get for retrieving a workcenter.
  • Added JobTracking Get for retrieving job progression and status information. This can be used to get a bird's-eye view of the job, including current operation(s), next operation(s) and estimates vs actuals so users have visibility into their shop floor.
  • Added Job Operation List for retrieving all operations for a job with related item to make and operation details.
  • Added OriginalScheduledStartUtc, OriginalScheduledEndUtc, ScheduledStartUtc and ScheduledEndUtc to all endpoints that return jobs. Affects Job List, Job Get and JobTracking Get

5/21/2024​

  • Added Attachment for adding an attachment to an entity.
  • Added Remote Attachment adding an attachment to an entity from a remote file location.

5/14/2024​

4/23/2024​

4/18/2024​

4/5/2024​

3/28/2024​

3/12/2024​

3/1/2024​

2/23/2024​

2/15/2024​

2/14/2024​

  • Added Paid Date to Invoice Update Status method for setting the paidDate property on an invoice
  • Added Item Routing Operation Batch for bulk applying operations to an item. Of note, this is geared towards nuance associated to continuous flow whereby operation order must be unique (no overlaps) but it can still be used if continuous flow is not enable. This will allow for bulk re-ordering operations, updating the existing operations where applicable, adding operations where they do not currently exist and removing no longer applicable operations.

2/13/2024​

  • Added Gauge Code for acquiring a gauge code that exists in Fulcrum tags.
  • Added Gauge Code List for searching for gauge codes that exists in Fulcrum tags.
  • Added Grade Code for acquiring a grade codes that exists in Fulcrum tags.
  • Added Grade Code List for searching for grade codes that exists in Fulcrum tags.
  • Added Material Code for acquiring a material codes that exists in Fulcrum tags.
  • Added Material Code List for searching for material codes that exists in Fulcrum tags.
  • Added Shape Code for acquiring a shape codes that exists in Fulcrum tags.
  • Added Shape Code List for searching for shape codes that exists in Fulcrum tags.
  • Updated Item Create to includes more fields (gauge, materialCode, shape, grade, height, length and width).
  • Added Item Update for updating an item. Minimal subset of fields.

1/29/2024​

1/26/2024​

1/16/2024​

12/13/2023​

12/12/2023​

12/7/2023​

11/13/2023​

  • Updated the Invoice endpoints to include 'Total', 'Subtotal', and 'NotesToCustomer' fields.

9/26/2023​

9/12/2023​

9/5/2023​

  • Scheduled start time, scheduled end time, and scheduled equipment ID added to the job item-to-make operation List/Read
  • Deprecated the status field in favour of statuses in the request body schema for [job List][api-schema#tag/Job/operation/ListJob] so that more than 1 job status can be filtered for at a time. status is Scheduled for removal EOD 2023-10-31.
  • Added the hasIncompleteOperations in the request body schema for [job List][api-schema#tag/Job/operation/ListJob] to filter for jobs with incomplete operations.

8/22/2023​

8/15/2023​

  • Deleted indicators added to Sales Order, Invoice and Purchase Order objects. While /list endpoints do not return deleted entities, you can still GET a deleted entity by it's Id. Having an indicator on the object will help your applications decide whether they can still make changes to that entity.

8/8/2023​

  • The Items List endpoint has been versioned. The new V2 Item List endpoint has a more robust item number matching options than the simple "contains" method of the original endpoint.

8/1/2023​

  • Add units of measure to Item Vendor Details.
  • Respect the IsTaxable value provided to the Customer create, update and patch endpoints.

7/25/2023​

  • Added ShipByDate to available filters as well as the response object of Shipments list.

7/18/2023​

7/12/2023​

5/1/2023​

  • Initial release