> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.useopenwrench.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Activos, tipos de activos, modelos, medidores y ubicaciones

> Gestiona ubicaciones y regiones, tipos y modelos de activos, creación de activos con seguimiento de refrigerante y lecturas de medidores en la Buyer API.

Todo lo que una orden de trabajo referencia vive aquí: **ubicaciones** (tus sitios físicos, agrupadas en **regiones**) y **activos** (equipos en una ubicación, clasificados por **tipo de activo**, opcionalmente estandarizados por **modelo de activo** e instrumentados con **medidores**).

Todos los ejemplos asumen:

```bash theme={null}
export BASE="https://api.useopenwrench.com/api/external"
export KEY="<your-api-key>"
export SECRET="<shared-secret>"
```

## Ubicaciones

Las ubicaciones son de lectura principalmente a través de la API:

```bash theme={null}
# Listar (el tamaño de página en este endpoint se limita a 10, aunque pidas más)
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/location/locations?limit=10"

# Contar coincidencias con un filtro
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/location/locations/count_by?regionId=4"

# Una ubicación, o varias en una sola llamada
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/location/locations/1204"
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/location/locations/multiple/1204,1205,1210"
```

Notas:

* El endpoint de listado limita `limit` a **10** (la mayoría de los listados permiten 25). Planifica los bucles de paginación en consecuencia.
* `multiple/{ids}` toma ids separados por coma y **omite silenciosamente** cualquier id sobre el que no tengas permiso de lectura; verifica qué ids llegaron en lugar de asumir que llegaron todos.
* La única escritura es `PATCH /v1/buyer/location/locations/{id}`, y lee **solo `locationTypeDetails`** del cuerpo (valores de campos personalizados del tipo de ubicación). Todos los demás campos se ignoran.

Las regiones agrupan ubicaciones: `GET /v1/buyer/location/regions` y `GET /v1/buyer/location/regions/{id}`.

## Tipos de activos

Los tipos de activos clasifican el equipamiento ("Walk-in cooler", "Rooftop unit") y llevan valores por defecto a nivel de clase, incluidas las configuraciones de refrigerante.

```bash theme={null}
curl -X POST "$BASE/v1/buyer/asset/asset_types" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Walk-in cooler",
    "usesRefrigerant": true,
    "refrigerantTypeCode": "R-448A",
    "fullChargeLb": 12.5
  }'
```

* `name` es el único campo obligatorio. `buyerCompanyId` se deriva de tu clave y no se puede establecer.
* `applianceCategory`, `refrigerantTypeCode` y `fullChargeLb` aceptan un **`null` explícito para borrar** el valor por defecto a nivel de clase. `fullChargeLb` debe ser positivo cuando se suministra.
* Pasar un `id` hace upsert sobre un tipo existente.

Lectura con `GET /v1/buyer/asset/asset_types` y `GET /v1/buyer/asset/asset_types/{id}`.

## Activos

Crea un activo con `POST /v1/buyer/asset/assets`. Obligatorios: `name`, `assetTypeId`, `locationId`, `isActive`, `isLeased`.

```bash theme={null}
curl -X POST "$BASE/v1/buyer/asset/assets" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Cooler #2 - back of house",
    "assetTypeId": 301,
    "locationId": 1204,
    "isActive": true,
    "isLeased": false,
    "serialNumber": "WC2-99841",
    "manufacturer": "Arctic Air",
    "assetModelId": 77,
    "installDate": "2024-05-01"
  }'
```

Comportamiento a conocer:

* `buyerFacilityId` y `buyerCompanyId` se **derivan de la ubicación**, nunca se leen del cuerpo.
* **Los overrides de refrigerante se pueden borrar.** `refrigerantTypeCode`, `fullChargeLb`, `applianceCategory` y `refrigerantRequiresProcessShutdown` son overrides por unidad de los valores por defecto del tipo de activo. Omitir la clave mantiene el valor almacenado; un `null` explícito (o cadena vacía) lo borra y vuelve a heredar del tipo. `isRefrigerantTracked` se comporta de forma similar: omitido o `null` mantiene el valor almacenado, y la inscripción solo se desactiva con un `false` explícito.
* **Subactivos.** `parentId` convierte esto en un subactivo. Requiere que los subactivos estén habilitados para tu empresa, y el hijo debe estar en la misma ubicación que el padre.
* Pasar un `id` hace upsert sobre un activo existente.

Lecturas:

```bash theme={null}
# Listado completo con filtros
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/assets?locationId=1204&limit=25"

# Proyección lite: id, name, type, serial, location, warranties
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/assets/asset_lite?locationId=1204"

# Un activo, hidratado con sus medidores
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/assets/5511"
```

`asset_lite` es la forma económica de sincronizar un selector de activos: cuando no pasas parámetros de paginación devuelve el **conjunto completo sin paginar**, con `count` igual al número de elementos devueltos. La lectura de un solo activo hidrata los medidores (el `type` de la envoltura es `ApiAssetWithMeter`).

## Etiquetas de activos

Las etiquetas de activos son marcadores ligeros que tu equipo define en la app de OpenWrench (un nombre más un color opcional), útiles para segmentar el listado de activos de formas que los campos integrados no cubren. A través de la API puedes leer el catálogo y reemplazar las etiquetas aplicadas a un activo. La creación y edición de las etiquetas en sí permanece en la app.

**Explora el catálogo** con `GET /v1/buyer/asset/asset_labels`, u obtén una con `GET /v1/buyer/asset/asset_labels/{id}`. El listado está limitado a las etiquetas de tu empresa y paginado a 10 por página por defecto. Acepta filtros `search` y `label` sobre el texto de la etiqueta. Pasa `no_pagination=true` para traer el catálogo completo en una sola llamada (el ordenamiento sigue aplicando).

```bash theme={null}
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  "$BASE/v1/buyer/asset/asset_labels?no_pagination=true"
```

**Reemplaza las etiquetas de un activo** con `PUT /v1/buyer/asset/assets/{assetId}/labels`. El cuerpo es `{ "ids": [...] }` y es un reemplazo completo: las etiquetas no listadas se eliminan, y un array vacío las borra todas. La respuesta lista las etiquetas ahora activas en el activo.

```bash theme={null}
curl -X PUT "$BASE/v1/buyer/asset/assets/5511/labels" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "ids": [7, 21] }'
```

Comportamiento a conocer:

* Un `ids` ausente o que no sea un array, o un id que no sea un número entero, se rechaza con `400`.
* Cada id debe ser una etiqueta viva del catálogo de tu empresa. Los ids desconocidos o de otro inquilino responden `400` con los ids problemáticos listados.
* La escritura requiere permiso de escritura de activos. Un id de activo desconocido, eliminado o ajeno responde el mismo `400` que una escritura denegada, no un `404`.

## Modelos de activos

Los modelos estandarizan especificaciones y manuales por tipo. `POST /v1/buyer/asset/asset_models` requiere `modelName` y `assetTypeId`, con `manuals` y `specs` opcionales como adjuntos.

El comparador difuso es útil durante importaciones, cuando tus datos de origen tienen nombres de modelo en texto libre:

```bash theme={null}
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  "$BASE/v1/buyer/asset/asset_models/fuzzy/Arctic%20Air%20WC-200/301"
```

`GET /v1/buyer/asset/asset_models/fuzzy/{name}/{assetTypeId}` devuelve el modelo más cercano dentro del tipo de activo, o `404` cuando nada es suficientemente parecido. Ante un `404`, cae al plan B de crear el modelo.

## Medidores y lecturas

Los medidores adjuntan una serie medible a un activo (temperatura, horas de funcionamiento, conteo de ciclos). Crea el medidor una vez y luego registra lecturas contra él:

```bash theme={null}
# 1. Crear el medidor
curl -X POST "$BASE/v1/buyer/asset/meters" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Box temperature",
    "assetId": 5511,
    "meterTypeId": 2,
    "readingMode": "direct_reading"
  }'

# 2. Registrar lecturas (por ejemplo desde un puente IoT)
curl -X POST "$BASE/v1/buyer/asset/meter_readings" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "meterId": 9310,
    "value": "38.2",
    "expectedValue": "36",
    "recordedAt": "2026-08-21T09:00:00.000-07:00",
    "recordedBy": "iot-bridge@example.com"
  }'

# 3. Listar, contar y obtener medidores y lecturas
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/meters?assetId=5511"
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/meters/count_by?assetId=5511"
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/meters/9310"

curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/meter_readings?meterId=9310"
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/meter_readings/count_by?meterId=9310"
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" "$BASE/v1/buyer/asset/meter_readings/40021"
```

Notas:

* `valueType`, `valueUnit` y `locationId` **no** se leen del cuerpo al crear el medidor: se derivan en el servidor a partir del activo y el tipo de medidor referenciados, así que enviarlos no tiene efecto.
* `readingMode` (renombrado desde `seriesType`) es uno de `direct_reading`, `change_from_baseline` o `compare_to_target`; por defecto es `direct_reading` cuando se omite.
* Los endpoints de listado y conteo de lecturas no están limitados a un solo medidor: abarcan todas las lecturas de tu empresa compradora a menos que filtres por `meterId`.
* Cuando el `readingMode` de un medidor es `change_from_baseline`, el `lastBaselineValue` de una lectura obtenida se calcula a partir de la lectura anterior más reciente marcada como `isBaseline` en ese medidor, según `recordedAt`; para los demás modos es `null`.

## Estrategia de sincronización

Para una sincronización nocturna de activos: pagina `asset_lite` por el conjunto de ids, compara contra tu sistema y luego obtén los registros completos por id solo para los activos modificados. Eso te mantiene dentro del límite de tasa (10 solicitudes por ventana de 20 segundos) con mucho más margen que paginar el listado completo a 25 por llamada.
