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

# Products

> Manage store products with full CRUD operations

## Overview

The Products API allows store owners to manage their product catalog with full create, read, update, and delete operations. All products are associated with a specific store and category.

## Create Product

<ParamField path="name" type="string" required>
  Product name (1-100 characters)
</ParamField>

<ParamField path="description" type="string">
  Product description (up to 1000 characters)
</ParamField>

<ParamField path="category" type="Id<'categories'>" required>
  Category ID for the product
</ParamField>

<ParamField path="price" type="number" required>
  Product price in USD
</ParamField>

<ParamField path="cost" type="number">
  Product cost for profit calculations
</ParamField>

<ParamField path="stock" type="number">
  Available stock quantity
</ParamField>

<ParamField path="stockAlert" type="number">
  Stock alert threshold
</ParamField>

<ParamField path="prepTime" type="number">
  Preparation time
</ParamField>

<ParamField path="prepTimeUnit" type="string">
  Time unit: `minutes`, `hours`, or `days`
</ParamField>

<ParamField path="isActive" type="boolean" required>
  Product availability status
</ParamField>

<ParamField path="primaryImage" type="Id<'_storage'>" required>
  Primary product image storage ID
</ParamField>

<ParamField path="images" type="Array<Id<'_storage'>>">
  Additional product images
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const productId = await convex.mutation(api.shared.products.createProduct, {
    name: "Pizza Margherita",
    description: "Classic Italian pizza with tomatoes, mozzarella, and basil",
    category: "k123456789",
    price: 15.99,
    cost: 8.50,
    stock: 100,
    stockAlert: 10,
    prepTime: 20,
    prepTimeUnit: "minutes",
    isActive: true,
    primaryImage: "s123456789",
    images: ["s123456789", "s987654321"]
  });
  ```

  ```javascript JavaScript theme={null}
  const productId = await convex.mutation("shared.products.createProduct", {
    name: "Pizza Margherita",
    description: "Classic Italian pizza with tomatoes, mozzarella, and basil",
    category: "k123456789",
    price: 15.99,
    cost: 8.50,
    stock: 100,
    stockAlert: 10,
    prepTime: 20,
    prepTimeUnit: "minutes",
    isActive: true,
    primaryImage: "s123456789",
    images: ["s123456789", "s987654321"]
  });
  ```

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

  response = requests.post(
      f"{CONVEX_URL}/api/mutation",
      json={
          "path": "shared.products.createProduct",
          "args": {
              "name": "Pizza Margherita",
              "description": "Classic Italian pizza with tomatoes, mozzarella, and basil",
              "category": "k123456789",
              "price": 15.99,
              "cost": 8.50,
              "stock": 100,
              "stockAlert": 10,
              "prepTime": 20,
              "prepTimeUnit": "minutes",
              "isActive": True,
              "primaryImage": "s123456789",
              "images": ["s123456789", "s987654321"]
          }
      },
      headers={"Authorization": f"Bearer {token}"}
  )

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

<ResponseExample>
  ```json Response theme={null}
  "p123456789"
  ```
</ResponseExample>

## Update Product

Update an existing product. Only provide the fields you want to change.

<ParamField path="productId" type="Id<'products'>" required>
  Product ID to update
</ParamField>

<ParamField path="name" type="string">
  Updated product name
</ParamField>

<ParamField path="description" type="string">
  Updated product description
</ParamField>

<ParamField path="price" type="number">
  Updated product price
</ParamField>

<ParamField path="stock" type="number">
  Updated stock quantity
</ParamField>

<ParamField path="isActive" type="boolean">
  Updated availability status
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const updatedProduct = await convex.mutation(api.shared.products.updateProduct, {
    productId: "p123456789",
    name: "Pizza Margherita Deluxe",
    price: 17.99,
    stock: 85,
    isActive: true
  });
  ```

  ```javascript JavaScript theme={null}
  const updatedProduct = await convex.mutation("shared.products.updateProduct", {
    productId: "p123456789",
    name: "Pizza Margherita Deluxe", 
    price: 17.99,
    stock: 85,
    isActive: true
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "_id": "p123456789",
    "name": "Pizza Margherita Deluxe",
    "description": "Classic Italian pizza with tomatoes, mozzarella, and basil",
    "price": 17.99,
    "stock": 85,
    "isActive": true,
    "primaryImageUrl": "https://storage.convex.dev/...",
    "imageUrls": ["https://storage.convex.dev/..."],
    "_creationTime": 1640995200000
  }
  ```
</ResponseExample>

## Get Products for Store

Retrieve all products for the authenticated store owner.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const products = await convex.query(api.shared.products.getProductsForStore);
  ```

  ```javascript JavaScript theme={null}
  const products = await convex.query("shared.products.getProductsForStore");
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  [
    {
      "_id": "p123456789",
      "name": "Pizza Margherita",
      "description": "Classic Italian pizza",
      "price": 15.99,
      "stock": 100,
      "isActive": true,
      "primaryImageUrl": "https://storage.convex.dev/...",
      "imageUrls": ["https://storage.convex.dev/..."],
      "category": {
        "id": "k123456789",
        "name": "Food"
      },
      "_creationTime": 1640995200000
    }
  ]
  ```
</ResponseExample>

## Get Product by ID

Retrieve a specific product by its ID.

<ParamField path="productId" type="Id<'products'>" required>
  Product ID to retrieve
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const product = await convex.query(api.shared.products.getProductById, {
    productId: "p123456789"
  });
  ```

  ```javascript JavaScript theme={null}
  const product = await convex.query("shared.products.getProductById", {
    productId: "p123456789"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "_id": "p123456789",
    "name": "Pizza Margherita",
    "description": "Classic Italian pizza with tomatoes, mozzarella, and basil",
    "price": 15.99,
    "cost": 8.50,
    "stock": 100,
    "stockAlert": 10,
    "prepTime": 20,
    "prepTimeUnit": "minutes",
    "isActive": true,
    "primaryImageUrl": "https://storage.convex.dev/...",
    "imageUrls": ["https://storage.convex.dev/..."],
    "category": {
      "id": "k123456789",
      "name": "Food"
    },
    "store": {
      "id": "j123456789",
      "name": "Mario's Pizza"
    },
    "_creationTime": 1640995200000
  }
  ```
</ResponseExample>

## Delete Product

Delete a product owned by the authenticated store owner.

<ParamField path="productId" type="Id<'products'>" required>
  Product ID to delete
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await convex.mutation(api.shared.products.deleteProduct, {
    productId: "p123456789"
  });
  ```

  ```javascript JavaScript theme={null}
  const result = await convex.mutation("shared.products.deleteProduct", {
    productId: "p123456789"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true
  }
  ```
</ResponseExample>

## Error Handling

<AccordionGroup>
  <Accordion title="Product not found">
    **Status Code**: `404`

    ```json theme={null}
    {
      "error": "Product not found or you don't have permission to access it"
    }
    ```
  </Accordion>

  <Accordion title="Validation errors">
    **Status Code**: `400`

    ```json theme={null}
    {
      "error": "Validation failed",
      "details": {
        "name": "Product name must be between 1 and 100 characters",
        "price": "Price must be a positive number"
      }
    }
    ```
  </Accordion>

  <Accordion title="Unauthorized">
    **Status Code**: `401`

    ```json theme={null}
    {
      "error": "Authentication required"
    }
    ```
  </Accordion>
</AccordionGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Image Optimization" icon="image">
    Upload images in WebP format for better performance. Use multiple sizes for responsive design.
  </Card>

  <Card title="Stock Management" icon="boxes-stacked">
    Set appropriate stock alerts to avoid overselling. Update stock levels in real-time.
  </Card>

  <Card title="SEO Optimization" icon="magnifying-glass">
    Use descriptive names and detailed descriptions for better search visibility.
  </Card>

  <Card title="Performance" icon="gauge-high">
    Batch operations when possible. Use pagination for large product catalogs.
  </Card>
</CardGroup>

<Note>
  Products are automatically indexed for search functionality. Changes to product information are reflected in search results within seconds.
</Note>

<Tip>
  Use the `cost` field to track profit margins and generate business intelligence reports.
</Tip>
