Skip to main content
Everything a work order points at lives here: locations (your physical sites, grouped into regions) and assets (equipment at a location, classified by asset type, optionally standardized by asset model, and instrumented with meters). All examples assume:

Locations

Locations are read-mostly through the API:
Notes:
  • The list endpoint clamps limit to 10 (most list endpoints allow 25). Plan pagination loops accordingly.
  • multiple/{ids} takes comma-separated ids and silently omits any id you lack read permission for; check which ids came back rather than assuming all did.
  • The only write is PATCH /v1/buyer/location/locations/{id}, and it reads only locationTypeDetails from the body (custom field values for the location’s type). All other fields are ignored.
Regions group locations: GET /v1/buyer/location/regions and GET /v1/buyer/location/regions/{id}.

Asset types

Asset types classify equipment (“Walk-in cooler”, “Rooftop unit”) and carry class-level defaults, including refrigerant settings.
  • name is the only required field. buyerCompanyId is derived from your key and cannot be set.
  • applianceCategory, refrigerantTypeCode, and fullChargeLb accept an explicit null to clear the class-level default. fullChargeLb must be positive when supplied.
  • Passing an id upserts an existing type.
Read with GET /v1/buyer/asset/asset_types and GET /v1/buyer/asset/asset_types/{id}.

Assets

Create an asset with POST /v1/buyer/asset/assets. Required: name, assetTypeId, locationId, isActive, isLeased.
Behavior to know:
  • buyerFacilityId and buyerCompanyId are derived from the location, never read from the body.
  • Refrigerant overrides are clearable. refrigerantTypeCode, fullChargeLb, applianceCategory, and refrigerantRequiresProcessShutdown are per-unit overrides of the asset type’s defaults. Omitting the key keeps the stored value; an explicit null (or blank string) clears it back to inheriting from the type. isRefrigerantTracked behaves similarly: omitted or null keeps the stored value, and enrollment is turned off only by an explicit false.
  • Sub-assets. parentId makes this a sub-asset. It requires sub-assets to be enabled for your company, and the child must be at the same location as the parent.
  • Passing an id upserts an existing asset.
Reads:
asset_lite is the cheap way to sync an asset picker: when you pass no pagination parameters it returns the unpaginated full set, with count equal to the number of items returned. The single-asset read hydrates meters (the envelope type reads ApiAssetWithMeter).

Asset labels

Asset labels are lightweight tags your team defines in the OpenWrench app (a name plus an optional color), useful for slicing the asset list in ways the built-in fields don’t cover. Through the API you can read the catalog and replace the labels applied to an asset. Creating or editing the labels themselves stays in the app. Browse the catalog with GET /v1/buyer/asset/asset_labels, or fetch one with GET /v1/buyer/asset/asset_labels/{id}. The list is scoped to your company’s labels and paginated 10 per page by default. It accepts search and label filters on the label text. Pass no_pagination=true to pull the whole catalog in one call (sorting still applies).
Replace an asset’s labels with PUT /v1/buyer/asset/assets/{assetId}/labels. The body is { "ids": [...] } and it is a full replacement: labels not listed are removed, and an empty array clears them all. The response lists the labels now active on the asset.
Behavior to know:
  • A missing or non-array ids, or an id that is not a whole number, is rejected with 400.
  • Every id must be a live label from your company’s catalog. Unknown or cross-tenant ids answer 400 with the offending ids listed.
  • The write requires asset write permission. An unknown, deleted, or foreign asset id answers the same 400 as a denied write, not a 404.

Asset models

Models standardize specs and manuals per type. POST /v1/buyer/asset/asset_models requires modelName and assetTypeId, with optional manuals and specs attachments. The fuzzy matcher is handy during imports, when your source data has free-text model names:
GET /v1/buyer/asset/asset_models/fuzzy/{name}/{assetTypeId} returns the closest model within the asset type, or 404 when nothing is sufficiently close. Fall back to creating the model on 404.

Meters and readings

Meters attach a measurable series to an asset (temperature, runtime hours, cycle counts). Create the meter once, then record readings against it:
Notes:
  • valueType, valueUnit, and locationId are not read from the create-meter body — they’re derived server-side from the referenced asset and meter type, so sending them has no effect.
  • readingMode (renamed from seriesType) is one of direct_reading, change_from_baseline, or compare_to_target; it defaults to direct_reading when omitted.
  • The meter-reading list and count endpoints aren’t scoped to a single meter — they span every reading across your buyer company unless you filter by meterId.
  • When a meter’s readingMode is change_from_baseline, a retrieved reading’s lastBaselineValue is computed from the most recent prior reading flagged isBaseline on that meter as of recordedAt; for other modes it’s null.

Sync strategy

For a nightly asset sync: page asset_lite for the id set, diff against your system, then fetch full records by id only for changed assets. That keeps you inside the rate limit (10 requests per 20-second window) far more comfortably than paging the full listing at 25 per call.