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

# Create Product

> Create a new product (master + default variant) in your workspace

## Authorization

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication. Format: `Bearer qwoty_your_token`
</ParamField>

## Request Body

<ParamField body="api_name" type="string" required>
  Unique API identifier (snake\_case). Can only contain lowercase letters,
  numbers and underscores.
</ParamField>

<ParamField body="recurrence_type" type="string" required>
  Billing model. Allowed values: `one_off`, `recurring`
</ParamField>

<ParamField body="name" type="string" required>
  Product name
</ParamField>

<ParamField body="reference" type="string">
  Internal reference code for the default variant
</ParamField>

<ParamField body="description" type="string">
  Product description
</ParamField>

<ParamField body="is_active" type="boolean" default="true">
  Active status
</ParamField>

<ParamField body="catalog_ids" type="string[]">
  Array of catalog UUIDs to link the product to. The workspace default catalog
  is always included automatically.
</ParamField>

<ParamField body="category_ids" type="string[]">
  Array of product category UUIDs to assign to this product.
</ParamField>

<ParamField body="inventory[sku]" type="string">
  Stock Keeping Unit
</ParamField>

<ParamField body="settings[unit_per_pack]" type="number">
  Number of units per pack
</ParamField>

<ParamField body="accounting[ledger_account]" type="string">
  Ledger account code
</ParamField>

<ParamField body="identifiers[crm]" type="string">
  External CRM identifier
</ParamField>

<ParamField body="identifiers[erp]" type="string">
  External ERP identifier
</ParamField>

<ParamField body="identifiers[accounting]" type="string">
  External accounting identifier
</ParamField>

<ParamField body="shipping[weight]" type="number">
  Shipping weight
</ParamField>

<ParamField body="shipping[weight_unit]" type="string">
  Weight unit. Allowed values: `kg`, `lbs`
</ParamField>

<ParamField body="shipping[height]" type="number">
  Shipping height
</ParamField>

<ParamField body="shipping[length]" type="number">
  Shipping length
</ParamField>

<ParamField body="shipping[width]" type="number">
  Shipping width
</ParamField>

<ParamField body="shipping[length_unit]" type="string">
  Length unit (e.g., `cm`, `in`)
</ParamField>

<ParamField body="shipping[country_of_origin]" type="string">
  ISO country code of origin
</ParamField>

<ParamField body="shipping[harmonized_system_code]" type="string">
  HS code for customs
</ParamField>

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://qwoty.app/api/products \
    -H "Authorization: Bearer qwoty_your_token" \
    -H "Content-Type: application/json" \
    -d '{
      "api_name": "premium_widget",
      "recurrence_type": "one_off",
      "name": "Premium Widget",
      "description": "High-quality widget for professional use",
      "reference": "PROD-001",
      "is_active": true,
      "catalog_ids": ["660e8400-e29b-41d4-a716-446655440001"],
      "category_ids": ["770e8400-e29b-41d4-a716-446655440002"],
      "inventory[sku]": "WID-PRE-001",
      "settings[unit_per_pack]": 1,
      "accounting[ledger_account]": "4010",
      "identifiers[crm]": "crm_123",
      "identifiers[erp]": "erp_456",
      "identifiers[accounting]": "acc_789",
      "shipping[weight]": 2.5,
      "shipping[weight_unit]": "kg",
      "shipping[height]": 10,
      "shipping[length]": 30,
      "shipping[width]": 20,
      "shipping[length_unit]": "cm",
      "shipping[country_of_origin]": "FR",
      "shipping[harmonized_system_code]": "8471.30"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://qwoty.app/api/products', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer qwoty_your_token',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      api_name: 'premium_widget',
      recurrence_type: 'one_off',
      name: 'Premium Widget',
      description: 'High-quality widget for professional use',
      reference: 'PROD-001',
      is_active: true,
      catalog_ids: ['660e8400-e29b-41d4-a716-446655440001'],
      category_ids: ['770e8400-e29b-41d4-a716-446655440002'],
      'inventory[sku]': 'WID-PRE-001',
      'settings[unit_per_pack]': 1,
      'accounting[ledger_account]': '4010',
      'identifiers[crm]': 'crm_123',
      'identifiers[erp]': 'erp_456',
      'identifiers[accounting]': 'acc_789',
      'shipping[weight]': 2.5,
      'shipping[weight_unit]': 'kg',
      'shipping[height]': 10,
      'shipping[length]': 30,
      'shipping[width]': 20,
      'shipping[length_unit]': 'cm',
      'shipping[country_of_origin]': 'FR',
      'shipping[harmonized_system_code]': '8471.30',
    }),
  })

  const data = await response.json()
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://qwoty.app/api/products',
      headers={
          'Authorization': 'Bearer qwoty_your_token',
          'Content-Type': 'application/json'
      },
      json={
          'api_name': 'premium_widget',
          'recurrence_type': 'one_off',
          'name': 'Premium Widget',
          'description': 'High-quality widget for professional use',
          'reference': 'PROD-001',
          'is_active': True,
          'catalog_ids': ['660e8400-e29b-41d4-a716-446655440001'],
          'category_ids': ['770e8400-e29b-41d4-a716-446655440002'],
          'inventory[sku]': 'WID-PRE-001',
          'settings[unit_per_pack]': 1,
          'accounting[ledger_account]': '4010',
          'identifiers[crm]': 'crm_123',
          'identifiers[erp]': 'erp_456',
          'identifiers[accounting]': 'acc_789',
          'shipping[weight]': 2.5,
          'shipping[weight_unit]': 'kg',
          'shipping[height]': 10,
          'shipping[length]': 30,
          'shipping[width]': 20,
          'shipping[length_unit]': 'cm',
          'shipping[country_of_origin]': 'FR',
          'shipping[harmonized_system_code]': '8471.30',
      }
  )

  data = response.json()
  ```
</CodeGroup>

## Response

<ResponseField name="success" type="boolean">
  Indicates if the request was successful
</ResponseField>

<ResponseField name="data" type="object">
  The created product object (variant structure, identical to `GET /api/products/{id}`)

  <Expandable title="Product Object">
    <ResponseField name="id" type="string">Product ID (UUID) — this is the default variant ID</ResponseField>
    <ResponseField name="product_parent_id" type="string">Parent product ID (UUID)</ResponseField>
    <ResponseField name="workspace_id" type="string">Workspace ID (UUID)</ResponseField>
    <ResponseField name="name" type="string">Product name</ResponseField>
    <ResponseField name="api_name" type="string">API identifier (creation-only, cannot be modified)</ResponseField>
    <ResponseField name="reference" type="string">Internal reference</ResponseField>
    <ResponseField name="description" type="string">Product description</ResponseField>
    <ResponseField name="is_active" type="boolean">Active status</ResponseField>
    <ResponseField name="is_default" type="boolean">Always `true` for the default variant</ResponseField>
    <ResponseField name="catalog_ids" type="array">Catalog IDs the product was linked to (includes the workspace default catalog)</ResponseField>
    <ResponseField name="category_ids" type="array">Category IDs linked to this product</ResponseField>
    <ResponseField name="product_ids" type="array">Array containing the default variant ID (same as `id`)</ResponseField>
    <ResponseField name="settings" type="object">Settings: `unit_per_pack`, `product_type`, `language_id`, `unit_of_measure`, `recurrence_type`</ResponseField>
    <ResponseField name="shipping" type="object">Shipping info: `weight`, `weight_unit`, `height`, `length`, `width`, `length_unit`, `country_of_origin`, `harmonized_system_code`</ResponseField>
    <ResponseField name="inventory" type="object">Inventory info: `sku`</ResponseField>
    <ResponseField name="identifiers" type="object">External identifiers: `crm`, `erp`, `accounting`</ResponseField>
    <ResponseField name="accounting" type="object">Accounting info: `ledger_account`</ResponseField>
    <ResponseField name="options" type="array">Option values (empty array for default variant)</ResponseField>

    <ResponseField name="prices" type="array">
      Prices created across all pricebooks for this product

      <Expandable title="Price Entry">
        <ResponseField name="id" type="string">Price ID (UUID)</ResponseField>
        <ResponseField name="pricebook_id" type="string">Pricebook ID (UUID)</ResponseField>
        <ResponseField name="pricebook_api_name" type="string">API name of the pricebook</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="primary_image_id" type="string | null">Primary image ID (null at creation)</ResponseField>
    <ResponseField name="parent_primary_image_id" type="string | null">Parent product primary image ID</ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json Success Response theme={null}
  {
    "success": true,
    "data": {
      "id": "880e8400-e29b-41d4-a716-446655440003",
      "product_parent_id": "550e8400-e29b-41d4-a716-446655440000",
      "workspace_id": "990e8400-e29b-41d4-a716-446655440004",
      "name": "Premium Widget",
      "api_name": "premium_widget",
      "reference": "PROD-001",
      "description": "High-quality widget for professional use",
      "description_inherit_from_product": true,
      "primary_image_inherit_from_product": true,
      "is_active": true,
      "is_default": true,
      "catalog_ids": ["660e8400-e29b-41d4-a716-446655440001"],
      "category_ids": ["770e8400-e29b-41d4-a716-446655440002"],
      "product_ids": ["880e8400-e29b-41d4-a716-446655440003"],
      "settings": {
        "unit_per_pack": 1,
        "product_type": null,
        "language_id": null,
        "unit_of_measure": null,
        "recurrence_type": "one_off"
      },
      "shipping": {
        "weight": 2.5,
        "weight_unit": "kg",
        "height": 10,
        "length": 30,
        "width": 20,
        "length_unit": "cm",
        "country_of_origin": "FR",
        "harmonized_system_code": "8471.30"
      },
      "inventory": {
        "sku": "WID-PRE-001"
      },
      "identifiers": {
        "crm": "crm_123",
        "erp": "erp_456",
        "accounting": "acc_789"
      },
      "accounting": {
        "ledger_account": "4010"
      },
      "options": [],
      "prices": [
        {
          "id": "price-001",
          "pricebook_id": "pb-001",
          "pricebook_api_name": "standard"
        }
      ],
      "primary_image_id": null,
      "parent_primary_image_id": null,
      "created_at": "2024-12-21T10:30:00Z",
      "updated_at": "2024-12-21T10:30:00Z"
    }
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json Validation Error theme={null}
  {
    "success": false,
    "error": "Validation error",
    "details": [
      "Field 'api_name' is required",
      "Field 'recurrence_type' is required (one_off | recurring)"
    ]
  }
  ```

  ```json Duplicate api_name theme={null}
  {
    "success": false,
    "error": "Validation error",
    "details": ["A product with api_name 'premium_widget' already exists"]
  }
  ```

  ```json Catalog Not Found theme={null}
  {
    "success": false,
    "error": "Validation error",
    "details": ["Catalog(s) not found: 660e8400-e29b-41d4-a716-446655440001"]
  }
  ```

  ```json Unauthorized theme={null}
  {
    "success": false,
    "error": "Invalid API token"
  }
  ```
</ResponseExample>
