Update Product Density
PUT/api/manufacturing/products/:product/density
Set or clear the product's density. The value is normalised to g/mL and stored with its provenance; inside the same transaction every weight↔volume unit on the product is re-derived from it (new factor, factor_source=density), pending cross-type rows get a factor, and overridden rows (is_override=true) are left alone. Clearing the density reverts density-derived rows to pending manual rows (factor 0) that need a factor before any BOM using them can be activated — so clearing must be confirmed with clear_derived when such rows exist.
Auth: requires Bearer token.
Path param: product = product id.
Body: value (required key, numeric or null — null clears the density); unit (required when value is set: g_ml | lb_gal | sg — lb/gal is converted, specific gravity is taken as g/mL); source (required when value is set: manual | supplier_spec | ai_lookup | measured); basis (optional, string, max 255 — temperature, lot, document reference, or the AI basis line); clear_derived (optional boolean — confirms that clearing may revert density-derived rows to pending manual rows; required to clear when any exist); suggestion (optional object, only with source=ai_lookup — the payload returned by Suggest Product Density, echoed back verbatim so the accepted value stays traceable on the product's activity log). It must carry exactly that shape and nothing else: suggestion.density_g_per_ml (required, numeric); suggestion.confidence (required: high | medium | low); suggestion.basis (required, string, max 255); suggestion.density_lb_per_gal and suggestion.specific_gravity (optional, numeric); suggestion.notes (optional, string, max 500); suggestion.alternatives (optional, array, max 3 — each with only label (required, string, max 100) and density_g_per_ml (required, numeric)); suggestion.cached (optional, boolean); suggestion.model (optional, string, max 100). Extra keys are rejected.
Range: after conversion the density must be greater than 0 and at most 30 g/mL.
manufacturing:writeGrant this scope to your token under Settings → Developer → Personal Access Tokens.
Response: the same payload as Get Product Density, plus units_of_measure (the product's full refreshed unit-of-measure rows — see List Product Units of Measure) and affected_boms (active bills of materials whose component lines consume this product in a density-dependent unit; manufacturing orders raised from them after this change use the new factors, existing orders are unaffected).
Response fields: density_g_per_ml (the stored value, g/mL; specific gravity is numerically equal), density_lb_per_gal (the same value in lb per US gallon), specific_gravity, source (manual | supplier_spec | ai_lookup | measured), basis (free text — temperature, lot, document reference, or the AI basis line), set_at, set_by (id + name), ai_lookup_available (whether Suggest Product Density can be called on this account), derived_rows (the product's weight↔volume rows whose factor comes from this density, each with uom_id, uom_code, factor and equation), pending_cross_type_uom_codes (weight↔volume units enabled on the product that are still waiting for a density before they get a factor). All density fields are null when no density is set.
Request
Responses
- 200
- 401
- 403
- 404
- 422
- 429
OK
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Not found — no record with the given identifier (or the route does not exist). Verify the ID before retrying.
Unprocessable Entity
Response Headers
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.