> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.coperniq.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.coperniq.io/_mcp/server.

# Create Catalog Item

POST https://api.coperniq.io/v1/catalog-items
Content-Type: application/json

Create a new catalog item.

Reference: https://docs.coperniq.io/api-reference/catalog-items/create-catalog-item

## Authentication

- `x-api-key` header (required) — API Key authentication via header

## Request

### Body (application/json)

This endpoint expects a CatalogItemCreate.

- `name` (string, required) — Catalog item name
- `type` (enum, required) — Catalog item type
  - Allowed values: `PRODUCT`, `SERVICE`
- `category` (CatalogCategoryCode, required) — Catalog item category code. Must be a valid ProductCategory when type is PRODUCT or ServiceCategory when type is SERVICE.
- `cost` (double, required) — Catalog item cost
- `price` (double, required) — Catalog item price
- `tradeGroup` (enum, optional) — High-level trade group for this item. If omitted, it is derived from the category — a product category resolves to the trade group it belongs to (for example ROOF_COVERING resolves to ENVELOPE), and services or category OTHER resolve to OTHER. When provided, it must be consistent with the category (for products, the category must belong to this trade group; category OTHER is allowed under any trade group).
  - Allowed values: `ENERGY`, `MECHANICAL`, `ELECTRICAL`, `PLUMBING`, `LOW_VOLTAGE`, `ENVELOPE`, `OTHER`
- `manufacturer` (string, optional, nullable) — Catalog item manufacturer
- `sku` (string, optional, nullable) — Catalog item SKU
- `code` (string, optional, nullable) — Catalog item code
- `description` (string, optional, nullable) — Catalog item description
- `preferredVendorId` (integer, optional, nullable) — ID of the preferred vendor (must be an existing active vendor for this company)
- `unitId` (integer, optional, nullable) — ID of the unit this item is sold/measured in. Must reference a unit belonging to your company (see GET /catalog-units).
- `measurementIds` (list of integer, optional) — IDs of measurements (and/or a single sub-measurement) to link to this item, driving its quantity calculation. At most one linked measurement may be a sub-measurement (type SUB_CALCULATION), and it must be the only one linked. Multiple plain measurement links must share the same unit (or be unitless) — their values are summed.
- `coverage` (double, optional, nullable) — Measurement units covered per item unit. Must be greater than zero. Not compatible with a linked sub-calculation, which derives quantity from its own formula.
- `wasteFactorMode` (enum, optional, nullable) — Waste factor mode. Must be set together with wasteFactorValue — both, or neither.
  - Allowed values: `STATIC`
- `wasteFactorValue` (double, optional, nullable) — Waste factor percentage (0-100). Must be set together with wasteFactorMode.

## Response

### 201

Catalog item created successfully

- `id` (integer, required) — Catalog item identifier
- `name` (string, required) — Catalog item name
- `catalog` (enum, required, nullable) — High-level trade group for this item.
  - Allowed values: `ENERGY`, `MECHANICAL`, `ELECTRICAL`, `PLUMBING`, `LOW_VOLTAGE`, `ENVELOPE`, `OTHER`
- `type` (enum, required) — Catalog item type
  - Allowed values: `PRODUCT`, `SERVICE`
- `category` (CatalogCategoryCode, required) — Catalog item category code (ProductCategory or ServiceCategory)
- `cost` (double, required, nullable) — Catalog item cost
- `price` (double, required, nullable) — Catalog item price
- `manufacturer` (string, optional, nullable) — Catalog item manufacturer
- `sku` (string, optional, nullable) — Catalog item SKU
- `code` (string, optional, nullable) — Catalog item code
- `description` (string, optional, nullable) — Catalog item description
- `image` (CatalogItemImage, optional, nullable)
- `isArchived` (boolean, optional, nullable) — Whether the catalog item is archived
- `createdById` (integer, optional) — Identifier of the user who created the catalog item
- `createdAt` (string, optional, nullable)
- `updatedAt` (string, optional, nullable)
- `preferredVendorId` (integer, optional, nullable) — ID of the preferred vendor (must be an existing active vendor for this company)
- `unit` (CatalogUnit, optional, nullable) — The unit this item is sold/measured in, if any. Set on write via `unitId`.
- `measurements` (list of Measurement, optional) — Measurements (and sub-measurements) linked to this item to drive its quantity calculation. A sub-measurement is a linked Measurement with `type SUB_CALCULATION`; at most one may be linked, and it must be the only link when present.
- `coverage` (double, optional, nullable) — Measurement units covered per item unit (e.g. a bundle covering ~33.33 SF). Used to size quantity from summed linked measurements; not used when the item is linked to a sub-calculation, which derives quantity from its own formula.
- `wasteFactorMode` (enum, optional, nullable) — Waste factor mode applied when computing this item's quantity. Currently only STATIC is supported. Paired with wasteFactorValue — both are set, or neither.
  - Allowed values: `STATIC`
- `wasteFactorValue` (double, optional, nullable) — Waste factor percentage (0-100) applied when computing this item's quantity. Paired with wasteFactorMode.

## Errors

### 400 Bad Request Error

Invalid request

- `message` (string, optional)
- `code` (enum, optional)
  - Allowed values: `UPSTREAM_ERROR`
- `field` (string, optional) — Field that caused the validation error (if applicable)

### 401 Unauthorized Error

Authentication failed

- `message` (string, optional)
- `code` (enum, optional)
  - Allowed values: `UPSTREAM_ERROR`

### 502 Bad Gateway Error

The catalog item was created, but could not be read back afterwards, so the full response (including any `unit` and `measurements` links) is unavailable. Use the returned `id` to fetch it with `GET /catalog-items/{catalog_item_id}` — do not retry this POST, which would create a duplicate. `id` is omitted only when the upstream write response itself contained no usable id.

- `code` (enum, optional)
  - Allowed values: `UPSTREAM_ERROR`
- `message` (string, optional)
- `id` (integer, optional) — The id of the catalog item that was created.

## Types

### CatalogCategoryCode

Catalog item category code. Must be: - one of `ProductCategory` when `type` is `PRODUCT`, or - one of `ServiceCategory` when `type` is `SERVICE`.

- ProductCategory: enum
  - Allowed values: `BATTERY_SYSTEM`, `BATTERY_MANAGEMENT_SYSTEM`, `CHARGING_GATEWAY`, `COMBINER_BOX`, `EV_CHARGER`, `LOAD_CENTER`, `MICROINVERTER`, `MOUNTING`, `POWER_OPTIMIZER`, `PRODUCTION_METER`, `PV_INVERTER`, `PV_MODULE`, `RACKING`, `RAPID_SHUTDOWN_DEVICE`, `TRACKER`, `WEATHER_STATION`, `AIR_CONDITIONER`, `AIR_HANDLING_UNIT`, `BOILER`, `CHILLER`, `COOLING_TOWER`, `FAN`, `HEAT_EXCHANGER`, `HEAT_PUMP`, `MAKE_UP_AIR_UNIT`, `PUMP`, `ROOFTOP_UNIT`, `THERMOSTAT`, `VARIABLE_FREQUENCY_DRIVE`, `AUTOMATIC_TRANSFER_SWITCH`, `BREAKER`, `DISCONNECT_SWITCH`, `ELECTRIC_METER`, `GENERATOR`, `LIGHTING_PANEL`, `PANELBOARD`, `SWITCHGEAR`, `TRANSFORMER`, `UNINTERRUPTIBLE_POWER_SUPPLY`, `WIRE`, `BACKFLOW_PREVENTER`, `BOOSTER_PUMP`, `GREASE_INTERCEPTOR`, `STORAGE_TANK`, `SUMP_PUMP`, `VALVE`, `WATER_FILTRATION_SYSTEM`, `WATER_HEATER`, `WATER_SOFTENER`, `ACCESS_CONTROLLER`, `AUTOMATION_CONTROLLER`, `CAMERA`, `CARD_READER`, `DOOR_STRIKE`, `MAGLOCK`, `NETWORK_SWITCH`, `NETWORK_VIDEO_RECORDER`, `SENSOR`, `WIRELESS_ACCESS_POINT`, `ROOF_COVERING`, `ROOF_UNDERLAYMENT`, `ROOF_MEMBRANE`, `ROOF_FLASHING`, `ROOF_VENT`, `WALL_CLADDING`, `WALL_TRIM`, `WEATHER_BARRIER`, `WINDOW`, `EXTERIOR_DOOR`, `SKYLIGHT`, `OPENING_FLASHING`, `GUTTER`, `DOWNSPOUT`, `INSULATION`, `SEALANT`, `SHEATHING`, `OTHER`
- ServiceCategory: enum
  - Allowed values: `ADJUSTMENT`, `BALANCING`, `CALIBRATION`, `CLEANING`, `COMMISSIONING`, `DECOMMISSIONING`, `DIAGNOSTICS`, `ENGINEERING`, `EQUIPMENT_RENTAL`, `INSPECTION`, `INSTALLATION`, `MAINTENANCE`, `MONITORING`, `OPTIMIZATION`, `PERMITTING`, `RELOCATION`, `REMOVAL`, `REPAIR`, `REPLACEMENT`, `RETROFIT`, `SITE_SURVEY`, `TESTING`, `TRAINING`, `OTHER`

### CatalogItemImage

- `id` (integer, optional)
- `name` (string, optional)
- `url` (string, optional) — URL to download the image

### CatalogUnit

A unit of measure from the company's unit registry (e.g. Each, Square Feet, Linear Feet). Referenced by catalog items and measurements via `unitId`.

- `id` (integer, required) — Catalog unit identifier
- `code` (string, required) — Stable short code for the unit (e.g. "SF", "EA")
- `label` (string, required) — Human-readable label for the unit (e.g. "Square Feet")
- `dimension` (enum, optional, nullable) — The physical dimension this unit measures, if any. Null for packaging-style units (e.g. bundle, roll) that can't be used on a measurement.
  - Allowed values: `LENGTH`, `AREA`, `COUNT`
- `isCustom` (boolean, optional) — Whether this unit was defined by the company, as opposed to one of the seeded defaults.
- `isArchived` (boolean, optional) — Whether this unit has been archived.

### Measurement

A named measurement or sub-calculation that a catalog item can link to (via `measurementIds`) to drive its quantity. A "sub-measurement" is simply a Measurement with `type: SUB_CALCULATION` — not a separate structure.

- `id` (integer, required) — Measurement identifier
- `name` (string, required) — Measurement name
- `type` (enum, required) — A plain MEASUREMENT is a raw input value; a SUB_CALCULATION ("sub-measurement") derives its value from a formula over other measurements.
  - Allowed values: `MEASUREMENT`, `SUB_CALCULATION`
- `unit` (CatalogUnit, optional, nullable) — The unit this measurement is expressed in, if any.
- `minimumValue` (double, optional, nullable) — Minimum allowed value. Only meaningful for type MEASUREMENT.
- `formula` (MeasurementFormula, optional) — The formula driving a SUB\_CALCULATION measurement's quantity. Read-only — there is no API to create or edit a measurement's formula; it can only be authored in the app. Shape: `operands` names each referenced measurement (`{name, measurementId}`); `ast` is a binary-operation tree (`ADD`/`SUB`/`MUL`/`DIV`) whose leaves are either `{operandRef}` (referencing an entry in `operands` by name) or `{constant}` (a literal number); `sourceText` is the original formula text as authored.
- `isArchived` (boolean, optional) — Whether this measurement has been archived.

### MeasurementFormula

The formula driving a SUB\_CALCULATION measurement's quantity. Read-only — there is no API to create or edit a measurement's formula; it can only be authored in the app. Shape: `operands` names each referenced measurement (`{name, measurementId}`); `ast` is a binary-operation tree (`ADD`/`SUB`/`MUL`/`DIV`) whose leaves are either `{operandRef}` (referencing an entry in `operands` by name) or `{constant}` (a literal number); `sourceText` is the original formula text as authored.

- `operands` (list of MeasurementFormulaOperandsItems, optional)
- `ast` (MeasurementFormulaAst, optional) — Binary-operation AST node or leaf. See the formula description above.
- `sourceText` (string, optional) — The formula as originally authored (e.g. "( m1 + m2 ) / 100")

### MeasurementFormulaOperandsItems

- `name` (string, optional)
- `measurementId` (integer, optional)

### MeasurementFormulaAst

Binary-operation AST node or leaf. See the formula description above.

## Examples

### Service example

**Request**

```json
{
  "name": "Installation",
  "type": "SERVICE",
  "category": "INSTALLATION",
  "cost": 300,
  "price": 600
}
```

**Response**

```json
{
  "id": 1,
  "name": "string",
  "catalog": "ENERGY",
  "type": "PRODUCT",
  "category": "BATTERY_SYSTEM",
  "cost": 1.1,
  "price": 1.1,
  "manufacturer": "string",
  "sku": "string",
  "code": "string",
  "description": "string",
  "image": {
    "id": 1,
    "name": "string",
    "url": "string"
  },
  "isArchived": true,
  "createdById": 1,
  "createdAt": "2024-01-15T09:30:00Z",
  "updatedAt": "2024-01-15T09:30:00Z",
  "preferredVendorId": 1,
  "unit": {
    "id": 1,
    "code": "string",
    "label": "string",
    "dimension": "LENGTH",
    "isCustom": true,
    "isArchived": true
  },
  "measurements": [
    {
      "id": 1,
      "name": "string",
      "type": "MEASUREMENT",
      "unit": {
        "id": 1,
        "code": "string",
        "label": "string",
        "dimension": "LENGTH",
        "isCustom": true,
        "isArchived": true
      },
      "minimumValue": 1.1,
      "formula": {
        "operands": [
          {
            "name": "string",
            "measurementId": 1
          }
        ],
        "ast": {},
        "sourceText": "string"
      },
      "isArchived": true
    }
  ],
  "coverage": 1.1,
  "wasteFactorMode": "STATIC",
  "wasteFactorValue": 1.1
}
```

**SDK Code**

```python Service example
import requests

url = "https://api.coperniq.io/v1/catalog-items"

payload = {
    "name": "Installation",
    "type": "SERVICE",
    "category": "INSTALLATION",
    "cost": 300,
    "price": 600
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Service example
const url = 'https://api.coperniq.io/v1/catalog-items';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"name":"Installation","type":"SERVICE","category":"INSTALLATION","cost":300,"price":600}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Service example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.coperniq.io/v1/catalog-items"

	payload := strings.NewReader("{\n  \"name\": \"Installation\",\n  \"type\": \"SERVICE\",\n  \"category\": \"INSTALLATION\",\n  \"cost\": 300,\n  \"price\": 600\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Service example
require 'uri'
require 'net/http'

url = URI("https://api.coperniq.io/v1/catalog-items")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"name\": \"Installation\",\n  \"type\": \"SERVICE\",\n  \"category\": \"INSTALLATION\",\n  \"cost\": 300,\n  \"price\": 600\n}"

response = http.request(request)
puts response.read_body
```

```java Service example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.coperniq.io/v1/catalog-items")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"name\": \"Installation\",\n  \"type\": \"SERVICE\",\n  \"category\": \"INSTALLATION\",\n  \"cost\": 300,\n  \"price\": 600\n}")
  .asString();
```

```php Service example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.coperniq.io/v1/catalog-items', [
  'body' => '{
  "name": "Installation",
  "type": "SERVICE",
  "category": "INSTALLATION",
  "cost": 300,
  "price": 600
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp Service example
using RestSharp;

var client = new RestClient("https://api.coperniq.io/v1/catalog-items");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"name\": \"Installation\",\n  \"type\": \"SERVICE\",\n  \"category\": \"INSTALLATION\",\n  \"cost\": 300,\n  \"price\": 600\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Service example
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "name": "Installation",
  "type": "SERVICE",
  "category": "INSTALLATION",
  "cost": 300,
  "price": 600
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.coperniq.io/v1/catalog-items")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Product with unit, measurement links, coverage, and waste factor

**Request**

```json
{
  "name": "Architectural Shingle",
  "type": "PRODUCT",
  "category": "ROOF_COVERING",
  "cost": 45,
  "price": 90,
  "tradeGroup": "ENVELOPE",
  "manufacturer": "Acme Roofing",
  "unitId": 1924,
  "measurementIds": [
    2727
  ],
  "coverage": 33.33,
  "wasteFactorMode": "STATIC",
  "wasteFactorValue": 10
}
```

**Response**

```json
{
  "id": 1,
  "name": "string",
  "catalog": "ENERGY",
  "type": "PRODUCT",
  "category": "BATTERY_SYSTEM",
  "cost": 1.1,
  "price": 1.1,
  "manufacturer": "string",
  "sku": "string",
  "code": "string",
  "description": "string",
  "image": {
    "id": 1,
    "name": "string",
    "url": "string"
  },
  "isArchived": true,
  "createdById": 1,
  "createdAt": "2024-01-15T09:30:00Z",
  "updatedAt": "2024-01-15T09:30:00Z",
  "preferredVendorId": 1,
  "unit": {
    "id": 1,
    "code": "string",
    "label": "string",
    "dimension": "LENGTH",
    "isCustom": true,
    "isArchived": true
  },
  "measurements": [
    {
      "id": 1,
      "name": "string",
      "type": "MEASUREMENT",
      "unit": {
        "id": 1,
        "code": "string",
        "label": "string",
        "dimension": "LENGTH",
        "isCustom": true,
        "isArchived": true
      },
      "minimumValue": 1.1,
      "formula": {
        "operands": [
          {
            "name": "string",
            "measurementId": 1
          }
        ],
        "ast": {},
        "sourceText": "string"
      },
      "isArchived": true
    }
  ],
  "coverage": 1.1,
  "wasteFactorMode": "STATIC",
  "wasteFactorValue": 1.1
}
```

**SDK Code**

```python Product with unit, measurement links, coverage, and waste factor
import requests

url = "https://api.coperniq.io/v1/catalog-items"

payload = {
    "name": "Architectural Shingle",
    "type": "PRODUCT",
    "category": "ROOF_COVERING",
    "cost": 45,
    "price": 90,
    "tradeGroup": "ENVELOPE",
    "manufacturer": "Acme Roofing",
    "unitId": 1924,
    "measurementIds": [2727],
    "coverage": 33.33,
    "wasteFactorMode": "STATIC",
    "wasteFactorValue": 10
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Product with unit, measurement links, coverage, and waste factor
const url = 'https://api.coperniq.io/v1/catalog-items';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"name":"Architectural Shingle","type":"PRODUCT","category":"ROOF_COVERING","cost":45,"price":90,"tradeGroup":"ENVELOPE","manufacturer":"Acme Roofing","unitId":1924,"measurementIds":[2727],"coverage":33.33,"wasteFactorMode":"STATIC","wasteFactorValue":10}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Product with unit, measurement links, coverage, and waste factor
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.coperniq.io/v1/catalog-items"

	payload := strings.NewReader("{\n  \"name\": \"Architectural Shingle\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"ROOF_COVERING\",\n  \"cost\": 45,\n  \"price\": 90,\n  \"tradeGroup\": \"ENVELOPE\",\n  \"manufacturer\": \"Acme Roofing\",\n  \"unitId\": 1924,\n  \"measurementIds\": [\n    2727\n  ],\n  \"coverage\": 33.33,\n  \"wasteFactorMode\": \"STATIC\",\n  \"wasteFactorValue\": 10\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Product with unit, measurement links, coverage, and waste factor
require 'uri'
require 'net/http'

url = URI("https://api.coperniq.io/v1/catalog-items")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"name\": \"Architectural Shingle\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"ROOF_COVERING\",\n  \"cost\": 45,\n  \"price\": 90,\n  \"tradeGroup\": \"ENVELOPE\",\n  \"manufacturer\": \"Acme Roofing\",\n  \"unitId\": 1924,\n  \"measurementIds\": [\n    2727\n  ],\n  \"coverage\": 33.33,\n  \"wasteFactorMode\": \"STATIC\",\n  \"wasteFactorValue\": 10\n}"

response = http.request(request)
puts response.read_body
```

```java Product with unit, measurement links, coverage, and waste factor
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.coperniq.io/v1/catalog-items")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"name\": \"Architectural Shingle\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"ROOF_COVERING\",\n  \"cost\": 45,\n  \"price\": 90,\n  \"tradeGroup\": \"ENVELOPE\",\n  \"manufacturer\": \"Acme Roofing\",\n  \"unitId\": 1924,\n  \"measurementIds\": [\n    2727\n  ],\n  \"coverage\": 33.33,\n  \"wasteFactorMode\": \"STATIC\",\n  \"wasteFactorValue\": 10\n}")
  .asString();
```

```php Product with unit, measurement links, coverage, and waste factor
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.coperniq.io/v1/catalog-items', [
  'body' => '{
  "name": "Architectural Shingle",
  "type": "PRODUCT",
  "category": "ROOF_COVERING",
  "cost": 45,
  "price": 90,
  "tradeGroup": "ENVELOPE",
  "manufacturer": "Acme Roofing",
  "unitId": 1924,
  "measurementIds": [
    2727
  ],
  "coverage": 33.33,
  "wasteFactorMode": "STATIC",
  "wasteFactorValue": 10
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp Product with unit, measurement links, coverage, and waste factor
using RestSharp;

var client = new RestClient("https://api.coperniq.io/v1/catalog-items");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"name\": \"Architectural Shingle\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"ROOF_COVERING\",\n  \"cost\": 45,\n  \"price\": 90,\n  \"tradeGroup\": \"ENVELOPE\",\n  \"manufacturer\": \"Acme Roofing\",\n  \"unitId\": 1924,\n  \"measurementIds\": [\n    2727\n  ],\n  \"coverage\": 33.33,\n  \"wasteFactorMode\": \"STATIC\",\n  \"wasteFactorValue\": 10\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Product with unit, measurement links, coverage, and waste factor
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "name": "Architectural Shingle",
  "type": "PRODUCT",
  "category": "ROOF_COVERING",
  "cost": 45,
  "price": 90,
  "tradeGroup": "ENVELOPE",
  "manufacturer": "Acme Roofing",
  "unitId": 1924,
  "measurementIds": [2727],
  "coverage": 33.33,
  "wasteFactorMode": "STATIC",
  "wasteFactorValue": 10
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.coperniq.io/v1/catalog-items")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 3

**Request**

```json
{
  "name": "Panel 400W",
  "type": "PRODUCT",
  "category": "PV_MODULE",
  "cost": 120.5,
  "price": 180,
  "tradeGroup": "ENERGY",
  "manufacturer": "Acme Solar"
}
```

**Response**

```json
{
  "id": 1,
  "name": "string",
  "catalog": "ENERGY",
  "type": "PRODUCT",
  "category": "BATTERY_SYSTEM",
  "cost": 1.1,
  "price": 1.1,
  "manufacturer": "string",
  "sku": "string",
  "code": "string",
  "description": "string",
  "image": {
    "id": 1,
    "name": "string",
    "url": "string"
  },
  "isArchived": true,
  "createdById": 1,
  "createdAt": "2024-01-15T09:30:00Z",
  "updatedAt": "2024-01-15T09:30:00Z",
  "preferredVendorId": 1,
  "unit": {
    "id": 1,
    "code": "string",
    "label": "string",
    "dimension": "LENGTH",
    "isCustom": true,
    "isArchived": true
  },
  "measurements": [
    {
      "id": 1,
      "name": "string",
      "type": "MEASUREMENT",
      "unit": {
        "id": 1,
        "code": "string",
        "label": "string",
        "dimension": "LENGTH",
        "isCustom": true,
        "isArchived": true
      },
      "minimumValue": 1.1,
      "formula": {
        "operands": [
          {
            "name": "string",
            "measurementId": 1
          }
        ],
        "ast": {},
        "sourceText": "string"
      },
      "isArchived": true
    }
  ],
  "coverage": 1.1,
  "wasteFactorMode": "STATIC",
  "wasteFactorValue": 1.1
}
```

**SDK Code**

```python
import requests

url = "https://api.coperniq.io/v1/catalog-items"

payload = {
    "name": "Panel 400W",
    "type": "PRODUCT",
    "category": "PV_MODULE",
    "cost": 120.5,
    "price": 180,
    "tradeGroup": "ENERGY",
    "manufacturer": "Acme Solar"
}
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.coperniq.io/v1/catalog-items';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"name":"Panel 400W","type":"PRODUCT","category":"PV_MODULE","cost":120.5,"price":180,"tradeGroup":"ENERGY","manufacturer":"Acme Solar"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.coperniq.io/v1/catalog-items"

	payload := strings.NewReader("{\n  \"name\": \"Panel 400W\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"PV_MODULE\",\n  \"cost\": 120.5,\n  \"price\": 180,\n  \"tradeGroup\": \"ENERGY\",\n  \"manufacturer\": \"Acme Solar\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.coperniq.io/v1/catalog-items")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"name\": \"Panel 400W\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"PV_MODULE\",\n  \"cost\": 120.5,\n  \"price\": 180,\n  \"tradeGroup\": \"ENERGY\",\n  \"manufacturer\": \"Acme Solar\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.coperniq.io/v1/catalog-items")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"name\": \"Panel 400W\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"PV_MODULE\",\n  \"cost\": 120.5,\n  \"price\": 180,\n  \"tradeGroup\": \"ENERGY\",\n  \"manufacturer\": \"Acme Solar\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.coperniq.io/v1/catalog-items', [
  'body' => '{
  "name": "Panel 400W",
  "type": "PRODUCT",
  "category": "PV_MODULE",
  "cost": 120.5,
  "price": 180,
  "tradeGroup": "ENERGY",
  "manufacturer": "Acme Solar"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.coperniq.io/v1/catalog-items");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"name\": \"Panel 400W\",\n  \"type\": \"PRODUCT\",\n  \"category\": \"PV_MODULE\",\n  \"cost\": 120.5,\n  \"price\": 180,\n  \"tradeGroup\": \"ENERGY\",\n  \"manufacturer\": \"Acme Solar\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "name": "Panel 400W",
  "type": "PRODUCT",
  "category": "PV_MODULE",
  "cost": 120.5,
  "price": 180,
  "tradeGroup": "ENERGY",
  "manufacturer": "Acme Solar"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.coperniq.io/v1/catalog-items")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```