# Components

The parts of a unit: compressors, fans, valves, controllers and the rest. A component is never deleted. When it is replaced, the old one is kept with the status `replaced` and the replacement goes into the service history, so the unit's history stays whole.

## The component model

- `id` (string (uuid))
- `unit_id` (string (uuid))
- `type` (string)
- `label` (string)
- `quantity` (integer)
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `status` (string) One of `active`, `replaced`, `removed`.
- `installed_at` (string (date), nullable)
- `removed_at` (string (date), nullable)
- `replaces_component_id` (string (uuid), nullable): The component this one replaced.
- `attributes` (object)
- `custom_fields` (object, nullable)
- `note` (string, nullable)
- `created_at` (string (date-time))
- `updated_at` (string (date-time))

## List components

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

The components of a unit.

### Path parameters

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

### Query parameters

- `include_replaced` (boolean): `true` includes earlier components.
- `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/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11/components \
  -H "Authorization: Bearer $MACI_API_KEY"
```

```javascript
const response = await fetch('https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11/components', {
  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/components",
    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/components', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 200

A page of components. The fields are those of the component model.

```json
{
  "data": [
    {
      "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 component

`POST /units/{unit}/components` · scope `units:write`

Add a component.

### Path parameters

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

### Headers

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

### Body (JSON)

- `type` (string, required) One of `compressor`, `condenser`, `evaporator`, `fan`, `expansion_device`, `controller`, `defrost_heater`, `sensor`, `valve`, `vessel`, `cabinet`, `maci_sensor`, `other`.
- `label` (string, required): The name of the component, such as `Compressor 1`.
- `quantity` (integer, nullable)
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `installed_at` (string (date), nullable)
- `note` (string, nullable)
- `attributes` (object, nullable): The type's own fields, such as `rated_current_a` and `motor_power_kw` for a compressor. Unknown fields are refused with 422.
- `custom_fields` (object, nullable): Fields of your own, as name and text. At most 20.

### Request

```bash
curl -X POST https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11/components \
  -H "Authorization: Bearer $MACI_API_KEY" \
  -H "Idempotency-Key: a-value-of-your-own" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "fan",
    "label": "Evaporator fan 1",
    "quantity": 2,
    "attributes": {
      "placement": "evaporator",
      "motor_type": "EC",
      "power_w": 38
    }
  }'
```

```javascript
const response = await fetch('https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11/components', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
    'Idempotency-Key': 'a-value-of-your-own',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "type": "fan",
    "label": "Evaporator fan 1",
    "quantity": 2,
    "attributes": {
      "placement": "evaporator",
      "motor_type": "EC",
      "power_w": 38
    }
  }),
});
const data = await response.json();
```

```python
import os
import requests

response = requests.post(
    "https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11/components",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}", "Idempotency-Key": "a-value-of-your-own"},
    json={
        "type": "fan",
        "label": "Evaporator fan 1",
        "quantity": 2,
        "attributes": {
            "placement": "evaporator",
            "motor_type": "EC",
            "power_w": 38
        }
    },
)
data = response.json()
```

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

$response = $client->request('POST', 'https://api.maci.energy/v1/units/0b6f4c1e-5a1d-4a57-9f0e-2f6f3f0c9a11/components', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
        'Idempotency-Key' => 'a-value-of-your-own',
    ],
    'json' => [
        'type' => 'fan',
        'label' => 'Evaporator fan 1',
        'quantity' => 2,
        'attributes' => [
            'placement' => 'evaporator',
            'motor_type' => 'EC',
            'power_w' => 38,
        ],
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 201

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

```json
{
  "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"
}
```

## Update component

`PATCH /components/{component}` · scope `units:write`

Change a component.

Send only the fields to change. A component that is replaced or removed cannot be changed (409).

### Path parameters

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

### Body (JSON)

- `label` (string): The name of the component, such as `Compressor 1`.
- `quantity` (integer, nullable)
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `installed_at` (string (date), nullable)
- `note` (string, nullable)
- `attributes` (object, nullable): The type's own fields, such as `rated_current_a` and `motor_power_kw` for a compressor. Unknown fields are refused with 422.
- `custom_fields` (object, nullable): Fields of your own, as name and text. At most 20.

### Request

```bash
curl -X PATCH https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66 \
  -H "Authorization: Bearer $MACI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Compressor 1",
    "quantity": 1,
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "installed_at": "2026-10-30"
  }'
```

```javascript
const response = await fetch('https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "label": "Compressor 1",
    "quantity": 1,
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "installed_at": "2026-10-30"
  }),
});
const data = await response.json();
```

```python
import os
import requests

response = requests.patch(
    "https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}"},
    json={
        "label": "Compressor 1",
        "quantity": 1,
        "manufacturer": "Example Ltd",
        "model": "K-100",
        "serial_no": "SN-204871",
        "installed_at": "2026-10-30"
    },
)
data = response.json()
```

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

$response = $client->request('PATCH', 'https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
    ],
    'json' => [
        'label' => 'Compressor 1',
        'quantity' => 1,
        'manufacturer' => 'Example Ltd',
        'model' => 'K-100',
        'serial_no' => 'SN-204871',
        'installed_at' => '2026-10-30',
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 200

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

```json
{
  "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"
}
```

## Replace component

`POST /components/{component}/replace` · scope `units:write`

Replace a component.

The new component gets the type of the old one. The old one is kept with the status `replaced`, and the replacement is in the service history.

### Path parameters

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

### Headers

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

### Body (JSON)

- `label` (string, required): The name of the component, such as `Compressor 1`.
- `quantity` (integer, nullable)
- `manufacturer` (string, nullable)
- `model` (string, nullable)
- `serial_no` (string, nullable)
- `installed_at` (string (date), nullable)
- `note` (string, nullable)
- `attributes` (object, nullable): The type's own fields, such as `rated_current_a` and `motor_power_kw` for a compressor. Unknown fields are refused with 422.
- `custom_fields` (object, nullable): Fields of your own, as name and text. At most 20.
- `service_text` (string, nullable): Text for the service note about the replacement.

### Request

```bash
curl -X POST https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66/replace \
  -H "Authorization: Bearer $MACI_API_KEY" \
  -H "Idempotency-Key: a-value-of-your-own" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Compressor 1",
    "quantity": 1,
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "installed_at": "2026-10-30",
    "attributes": {}
  }'
```

```javascript
const response = await fetch('https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66/replace', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MACI_API_KEY}`,
    'Idempotency-Key': 'a-value-of-your-own',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "label": "Compressor 1",
    "quantity": 1,
    "manufacturer": "Example Ltd",
    "model": "K-100",
    "serial_no": "SN-204871",
    "installed_at": "2026-10-30",
    "attributes": {}
  }),
});
const data = await response.json();
```

```python
import os
import requests

response = requests.post(
    "https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66/replace",
    headers={"Authorization": f"Bearer {os.environ['MACI_API_KEY']}", "Idempotency-Key": "a-value-of-your-own"},
    json={
        "label": "Compressor 1",
        "quantity": 1,
        "manufacturer": "Example Ltd",
        "model": "K-100",
        "serial_no": "SN-204871",
        "installed_at": "2026-10-30",
        "attributes": {}
    },
)
data = response.json()
```

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

$response = $client->request('POST', 'https://api.maci.energy/v1/components/c2a9d7f4-1b7e-4e0a-8f55-3a9b1d2c4e66/replace', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('MACI_API_KEY'),
        'Idempotency-Key' => 'a-value-of-your-own',
    ],
    'json' => [
        'label' => 'Compressor 1',
        'quantity' => 1,
        'manufacturer' => 'Example Ltd',
        'model' => 'K-100',
        'serial_no' => 'SN-204871',
        'installed_at' => '2026-10-30',
        'attributes' => [],
    ],
]);
$data = json_decode($response->getBody(), true);
```

### Response 201

The new component. The fields are those of the component model.

```json
{
  "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": "8d1f3a2c-5b4e-4c7d-9e0f-1a2b3c4d5e6f",
  "attributes": {},
  "custom_fields": null,
  "note": null,
  "created_at": "2026-10-30T09:15:00Z",
  "updated_at": "2026-10-30T09:15:00Z"
}
```
