# Units

A unit is one refrigeration system, display case, cold room or other piece of equipment with its own QR or NFC tag, and a site is where it stands. A unit has master data from its nameplate, its refrigerant and charge with the CO2 equivalent worked out, and its active components. The API reaches the units the organisation owns and, for a service company, the units where it has an active grant.

## The unit model

- `id` (string (uuid))
- `public_id` (string): The Maci ID, such as `MC-0482`.
- `name` (string)
- `category` (string)
- `status` (string) One of `active`, `decommissioned`.
- `organization_id` (string (uuid)): The owner.
- `site_id` (string (uuid), nullable)
- `parent_unit_id` (string (uuid), nullable)
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `production_year` (integer, nullable)
- `installation_year` (integer, nullable)
- `system_type` (string, nullable)
- `refrigerant` (string, nullable): The designation of the refrigerant.
- `charge_kg` (number, nullable)
- `co2e_tonnes` (number, nullable): The charge in tonnes of CO2 equivalent.
- `charge_is_on_parent` (boolean): `true` when refrigerant and charge are those of the central system.
- `premium` (boolean): Whether the unit has Premium. The API only reaches units that have it.
- `hermetically_sealed` (boolean)
- `leak_detection_system` (boolean)
- `temp_min_c` (number, nullable)
- `temp_max_c` (number, nullable)
- `supply_voltage_v` (integer, nullable)
- `supply_phases` (integer, nullable)
- `supply_frequency_hz` (integer, nullable)
- `rated_current_a` (number, nullable): Rated current in A, from the nameplate.
- `power_kw` (number, nullable): Power in kW, from the nameplate.
- `ps_high_bar` (number, nullable): Allowable pressure PS on the high side, in bar.
- `ps_low_bar` (number, nullable): Allowable pressure PS on the low side, in bar.
- `climate_class` (string, nullable)
- `created_at` (string (date-time))
- `updated_at` (string (date-time))
- `components` (array): Active components. Only there when one unit is fetched. See the component model.

## The site model

- `id` (string (uuid))
- `organization_id` (string (uuid))
- `name` (string)
- `address` (string, nullable)
- `created_at` (string (date-time))
- `updated_at` (string (date-time))

## List sites

`GET /sites` · scope `units:read`

The organisation's sites.

The organisation's own sites. For a service company also the sites where the company has access to units.

### Query parameters

- `limit` (integer): Records per page. At most 100, default 50.
- `cursor` (string): The value of `next_cursor` from the page before.

### Request

```bash
curl https://api.maci.energy/v1/sites \
  -H "Authorization: Bearer $MACI_API_KEY"
```

```javascript
const response = await fetch('https://api.maci.energy/v1/sites', {
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
  },
});
const data = await response.json();
```

```python
import os
import requests

response = requests.get(
    "https://api.maci.energy/v1/sites",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}"},
)
data = response.json()
```

```php
$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.maci.energy/v1/sites', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 200

A page of sites. The fields are those of the site model.

```json
{
  "data": [
    {
      "id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
      "organization_id": "a3f1c2d4-6b8e-4f0a-9c1d-2e3f4a5b6c7d",
      "name": "Main store",
      "address": "Example Street 1, 2100 Copenhagen",
      "created_at": "2026-10-30T09:15:00Z",
      "updated_at": "2026-10-30T09:15:00Z"
    }
  ],
  "next_cursor": null
}
```

## List units

`GET /units` · scope `units:read`

The units the organisation has access to.

### Query parameters

- `site_id` (string (uuid)): Only units at this site.
- `status` (string): Only units with this status, `active` or `decommissioned`. One of `active`, `decommissioned`.
- `updated_since` (string (date-time)): Only units changed at or after this time.
- `limit` (integer): Records per page. At most 100, default 50.
- `cursor` (string): The value of `next_cursor` from the page before.

### Request

```bash
curl https://api.maci.energy/v1/units \
  -H "Authorization: Bearer $MACI_API_KEY"
```

```javascript
const response = await fetch('https://api.maci.energy/v1/units', {
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
  },
});
const data = await response.json();
```

```python
import os
import requests

response = requests.get(
    "https://api.maci.energy/v1/units",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}"},
)
data = response.json()
```

```php
$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.maci.energy/v1/units', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 200

A page of units, without components. The fields are those of the unit model.

```json
{
  "data": [
    {
      "id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
      "public_id": "MC-0482",
      "name": "Cold room 2",
      "category": "cold_room",
      "status": "active",
      "organization_id": "a3f1c2d4-6b8e-4f0a-9c1d-2e3f4a5b6c7d",
      "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
      "parent_unit_id": null,
      "manufacturer": "Example Ltd",
      "model": "K-100",
      "serial_no": "SN-204871",
      "production_year": 2019,
      "installation_year": 2020,
      "system_type": "split",
      "refrigerant": "R449A",
      "charge_kg": 42,
      "co2e_tonnes": 58.7,
      "charge_is_on_parent": false,
      "premium": true,
      "hermetically_sealed": false,
      "leak_detection_system": false,
      "temp_min_c": 0,
      "temp_max_c": 4,
      "supply_voltage_v": 400,
      "supply_phases": 3,
      "supply_frequency_hz": 50,
      "rated_current_a": 12.4,
      "power_kw": 5.5,
      "ps_high_bar": 28,
      "ps_low_bar": 19,
      "climate_class": "N",
      "created_at": "2026-10-30T09:15:00Z",
      "updated_at": "2026-10-30T09:15:00Z",
      "components": [
        {
          "id": "c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66",
          "unit_id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
          "type": "compressor",
          "label": "Compressor 1",
          "quantity": 1,
          "manufacturer": "Example Ltd",
          "model": "K-100",
          "serial_no": "SN-204871",
          "status": "active",
          "installed_at": "2026-10-30",
          "removed_at": null,
          "replaces_component_id": null,
          "attributes": {},
          "custom_fields": null,
          "note": null,
          "created_at": "2026-10-30T09:15:00Z",
          "updated_at": "2026-10-30T09:15:00Z"
        }
      ]
    }
  ],
  "next_cursor": null
}
```

## Create unit

`POST /units` · scope `units:write`

Create a unit.

The unit is created at one of the organisation's sites. A service company can create at a customer's site when its grant includes creation.

### Headers

- `Idempotency-Key` (string): A value of your own choosing, so that a repeated call does not create two records.

### Body (JSON)

- `site_id` (string (uuid), required): The site the unit is at.
- `name` (string, required): The name of the unit.
- `category` (string, required) One of `display_case`, `freezer_case`, `plug_in_cabinet`, `cold_room`, `freezer_room`, `blast_chiller`, `condensing_unit`, `compressor_rack`, `chiller`, `heat_pump`, `other`.
- `tag_code` (string, nullable): The code on a pre-printed label that is not in use. The unit gets the Maci ID of the label. Not in the sandbox.
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `production_year` (integer, nullable)
- `installation_year` (integer, nullable)
- `system_type` (string, nullable) One of `plug_in`, `split`, `central`.
- `parent_unit_id` (string (uuid), nullable): The central system the unit is connected to. It has to be one of the owner's units.
- `refrigerant` (string, nullable): The designation of the refrigerant, such as `R449A`. See GET /refrigerants.
- `refrigerant_id` (string (uuid), nullable): The ID of the refrigerant. Can be used instead of `refrigerant`.
- `charge_kg` (number, nullable): The charge in kg.
- `hermetically_sealed` (boolean)
- `leak_detection_system` (boolean)
- `temp_min_c` (number, nullable)
- `temp_max_c` (number, nullable)
- `supply_voltage_v` (integer, nullable)
- `supply_phases` (integer, nullable) One of `1`, `3`.
- `supply_frequency_hz` (integer, nullable) One of `50`, `60`.
- `rated_current_a` (number, nullable): Rated current in A, from the nameplate.
- `power_kw` (number, nullable): Power in kW, from the nameplate.
- `ps_high_bar` (number, nullable): Allowable pressure PS on the high side, in bar.
- `ps_low_bar` (number, nullable): Allowable pressure PS on the low side, in bar.
- `climate_class` (string, nullable)

### Request

```bash
curl -X POST https://api.maci.energy/v1/units \
  -H "Authorization: Bearer $MACI_API_KEY" \
  -H "Idempotency-Key: a-value-of-your-own" \
  -H "Content-Type: application/json" \
  -d '{
    "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
    "tag_code": "MC-0482",
    "name": "Cold room 2",
    "category": "cold_room",
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "production_year": 2019,
    "installation_year": 2020
  }'
```

```javascript
const response = await fetch('https://api.maci.energy/v1/units', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
    'Idempotency-Key': 'a-value-of-your-own',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
    "tag_code": "MC-0482",
    "name": "Cold room 2",
    "category": "cold_room",
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "production_year": 2019,
    "installation_year": 2020
  }),
});
const data = await response.json();
```

```python
import os
import requests

response = requests.post(
    "https://api.maci.energy/v1/units",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}", "Idempotency-Key": "a-value-of-your-own"},
    json={
        "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
        "tag_code": "MC-0482",
        "name": "Cold room 2",
        "category": "cold_room",
        "manufacturer": "Example Ltd",
        "model": "K-100",
        "serial_no": "SN-204871",
        "production_year": 2019,
        "installation_year": 2020
    },
)
data = response.json()
```

```php
$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.maci.energy/v1/units', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
        'Idempotency-Key' => 'a-value-of-your-own',
    ],
    'json' => [
        'site_id' => '5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30',
        'tag_code' => 'MC-0482',
        'name' => 'Cold room 2',
        'category' => 'cold_room',
        'manufacturer' => 'Example Ltd',
        'model' => 'K-100',
        'serial_no' => 'SN-204871',
        'production_year' => 2019,
        'installation_year' => 2020,
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 201

The unit that was created. The fields are those of the unit model.

```json
{
  "id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
  "public_id": "MC-0482",
  "name": "Cold room 2",
  "category": "cold_room",
  "status": "active",
  "organization_id": "a3f1c2d4-6b8e-4f0a-9c1d-2e3f4a5b6c7d",
  "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
  "parent_unit_id": null,
  "manufacturer": "Example Ltd",
  "model": "K-100",
  "serial_no": "SN-204871",
  "production_year": 2019,
  "installation_year": 2020,
  "system_type": "split",
  "refrigerant": "R449A",
  "charge_kg": 42,
  "co2e_tonnes": 58.7,
  "charge_is_on_parent": false,
  "premium": true,
  "hermetically_sealed": false,
  "leak_detection_system": false,
  "temp_min_c": 0,
  "temp_max_c": 4,
  "supply_voltage_v": 400,
  "supply_phases": 3,
  "supply_frequency_hz": 50,
  "rated_current_a": 12.4,
  "power_kw": 5.5,
  "ps_high_bar": 28,
  "ps_low_bar": 19,
  "climate_class": "N",
  "created_at": "2026-10-30T09:15:00Z",
  "updated_at": "2026-10-30T09:15:00Z",
  "components": [
    {
      "id": "c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66",
      "unit_id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
      "type": "compressor",
      "label": "Compressor 1",
      "quantity": 1,
      "manufacturer": "Example Ltd",
      "model": "K-100",
      "serial_no": "SN-204871",
      "status": "active",
      "installed_at": "2026-10-30",
      "removed_at": null,
      "replaces_component_id": null,
      "attributes": {},
      "custom_fields": null,
      "note": null,
      "created_at": "2026-10-30T09:15:00Z",
      "updated_at": "2026-10-30T09:15:00Z"
    }
  ]
}
```

## Get unit

`GET /units/{unit}` · scope `units:read`

Master data, refrigerant, charge and active components.

### Path parameters

- `unit` (string (uuid), required): The ID of the unit.

### Request

```bash
curl https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11 \
  -H "Authorization: Bearer $MACI_API_KEY"
```

```javascript
const response = await fetch('https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11', {
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
  },
});
const data = await response.json();
```

```python
import os
import requests

response = requests.get(
    "https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}"},
)
data = response.json()
```

```php
$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 200

The unit with its active components. The fields are those of the unit model.

```json
{
  "id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
  "public_id": "MC-0482",
  "name": "Cold room 2",
  "category": "cold_room",
  "status": "active",
  "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
  "refrigerant": "R449A",
  "charge_kg": 42,
  "co2e_tonnes": 58.7,
  "components": [
    {
      "id": "c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66",
      "type": "compressor",
      "label": "Compressor 1",
      "manufacturer": "Example Ltd",
      "model": "K-100",
      "status": "active",
      "attributes": {
        "rated_current_a": 9.8,
        "motor_power_kw": 3.7
      }
    }
  ]
}
```

## Update unit

`PATCH /units/{unit}` · scope `units:write`

Change master data.

Send only the fields to change.

### Path parameters

- `unit` (string (uuid), required): The ID of the unit.

### Body (JSON)

- `name` (string): The name of the unit.
- `category` (string) One of `display_case`, `freezer_case`, `plug_in_cabinet`, `cold_room`, `freezer_room`, `blast_chiller`, `condensing_unit`, `compressor_rack`, `chiller`, `heat_pump`, `other`.
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `production_year` (integer, nullable)
- `installation_year` (integer, nullable)
- `system_type` (string, nullable) One of `plug_in`, `split`, `central`.
- `parent_unit_id` (string (uuid), nullable): The central system the unit is connected to. It has to be one of the owner's units.
- `refrigerant` (string, nullable): The designation of the refrigerant, such as `R449A`. See GET /refrigerants.
- `refrigerant_id` (string (uuid), nullable): The ID of the refrigerant. Can be used instead of `refrigerant`.
- `charge_kg` (number, nullable): The charge in kg.
- `hermetically_sealed` (boolean)
- `leak_detection_system` (boolean)
- `temp_min_c` (number, nullable)
- `temp_max_c` (number, nullable)
- `supply_voltage_v` (integer, nullable)
- `supply_phases` (integer, nullable) One of `1`, `3`.
- `supply_frequency_hz` (integer, nullable) One of `50`, `60`.
- `rated_current_a` (number, nullable): Rated current in A, from the nameplate.
- `power_kw` (number, nullable): Power in kW, from the nameplate.
- `ps_high_bar` (number, nullable): Allowable pressure PS on the high side, in bar.
- `ps_low_bar` (number, nullable): Allowable pressure PS on the low side, in bar.
- `climate_class` (string, nullable)

### Request

```bash
curl -X PATCH https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11 \
  -H "Authorization: Bearer $MACI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Cold room 2",
    "category": "cold_room",
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "production_year": 2019
  }'
```

```javascript
const response = await fetch('https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Cold room 2",
    "category": "cold_room",
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "production_year": 2019
  }),
});
const data = await response.json();
```

```python
import os
import requests

response = requests.patch(
    "https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}"},
    json={
        "name": "Cold room 2",
        "category": "cold_room",
        "manufacturer": "Example Ltd",
        "model": "K-100",
        "serial_no": "SN-204871",
        "production_year": 2019
    },
)
data = response.json()
```

```php
$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
    ],
    'json' => [
        'name' => 'Cold room 2',
        'category' => 'cold_room',
        'manufacturer' => 'Example Ltd',
        'model' => 'K-100',
        'serial_no' => 'SN-204871',
        'production_year' => 2019,
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 200

The unit after the change. The fields are those of the unit model.

```json
{
  "id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
  "public_id": "MC-0482",
  "name": "Cold room 2",
  "category": "cold_room",
  "status": "active",
  "organization_id": "a3f1c2d4-6b8e-4f0a-9c1d-2e3f4a5b6c7d",
  "site_id": "5d0c7e52-8a0b-4c3e-b1a4-7c1f6a2d9e30",
  "parent_unit_id": null,
  "manufacturer": "Example Ltd",
  "model": "K-100",
  "serial_no": "SN-204871",
  "production_year": 2019,
  "installation_year": 2020,
  "system_type": "split",
  "refrigerant": "R449A",
  "charge_kg": 42,
  "co2e_tonnes": 58.7,
  "charge_is_on_parent": false,
  "premium": true,
  "hermetically_sealed": false,
  "leak_detection_system": false,
  "temp_min_c": 0,
  "temp_max_c": 4,
  "supply_voltage_v": 400,
  "supply_phases": 3,
  "supply_frequency_hz": 50,
  "rated_current_a": 12.4,
  "power_kw": 5.5,
  "ps_high_bar": 28,
  "ps_low_bar": 19,
  "climate_class": "N",
  "created_at": "2026-10-30T09:15:00Z",
  "updated_at": "2026-10-30T09:15:00Z",
  "components": [
    {
      "id": "c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66",
      "unit_id": "0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11",
      "type": "compressor",
      "label": "Compressor 1",
      "quantity": 1,
      "manufacturer": "Example Ltd",
      "model": "K-100",
      "serial_no": "SN-204871",
      "status": "active",
      "installed_at": "2026-10-30",
      "removed_at": null,
      "replaces_component_id": null,
      "attributes": {},
      "custom_fields": null,
      "note": null,
      "created_at": "2026-10-30T09:15:00Z",
      "updated_at": "2026-10-30T09:15:00Z"
    }
  ]
}
```
