# Catalog API Documentation

## Overview

The Catalog API provides public, company-scoped endpoints for mobile apps to browse products and categories. These endpoints **do not require authentication** but mandate the `X-Company-Hash` header to identify the company.

**Base URL:** `https://adminv2.missio.io/api/catalog`

**Required Headers:**
- `X-Company-Hash`: Company identifier (required for all requests)
- `Content-Type`: application/json

---

## Endpoints

### 1. Get Categories

Retrieve the category tree for the company (top-level categories with nested children).

**Endpoint:** `GET /api/catalog/categories`

**Headers:**
```
X-Company-Hash: your-company-hash
```

**Response:**
```json
{
  "status": "success",
  "message": "Categories fetched",
  "categories": [
    {
      "id": 1,
      "category_name": "Electronics",
      "slug": "electronics",
      "image": "https://example.com/user-uploads/product-category/1/category.jpg",
      "parent_id": null,
      "position": 1,
      "status": 1,
      "children_recursive": [
        {
          "id": 5,
          "category_name": "Phones",
          "slug": "phones",
          "image": "https://example.com/user-uploads/product-category/5/phones.jpg",
          "parent_id": 1,
          "position": 1,
          "status": 1,
          "children_recursive": []
        }
      ]
    }
  ]
}
```

---

### 2. List Products

List products with pagination, search, filtering, and sorting capabilities.

**Endpoint:** `GET /api/catalog/products`

**Headers:**
```
X-Company-Hash: your-company-hash
```

**Query Parameters:**

| Parameter | Type | Required | Description | Example |
|-----------|------|----------|-------------|---------|
| `search` | string | No | Full-text search on product name and description | `shoe` |
| `category_slug` | string | No | Filter by category slug (includes descendants) | `electronics` |
| `category_id` | integer | No | Alternative filter by category ID | `5` |
| `min_price` | float | No | Minimum price filter | `10.00` |
| `max_price` | float | No | Maximum price filter | `100.00` |
| `sort` | string | No | Sort order: `name`, `date`, `price`, `price-desc`, `popularity` | `price` |
| `page` | integer | No | Page number (default: 1) | `2` |
| `per_page` | integer | No | Items per page (1-100, default: 20) | `50` |

**Response:**
```json
{
  "status": "success",
  "message": "Products fetched",
  "products": {
    "current_page": 1,
    "data": [
      {
        "id": 1008,
        "name": "Running Shoes",
        "slug": "running-shoes",
        "price": 100,
        "min_price": 80,
        "max_price": 120,
        "short_description": "Comfortable running shoes for daily use",
        "images": {
          "sm": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/sm_image.jpg",
          "md": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/md_image.jpg",
          "lg": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/lg_image.jpg",
          "original": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/image.jpg"
        },
        "views": 150,
        "categories": [
          {
            "id": 5,
            "category_name": "Footwear",
            "slug": "footwear",
            "parent_id": null
          }
        ]
      }
    ],
    "first_page_url": "http://api.example.com/api/catalog/products?page=1",
    "from": 1,
    "last_page": 5,
    "last_page_url": "http://api.example.com/api/catalog/products?page=5",
    "links": [...],
    "next_page_url": "http://api.example.com/api/catalog/products?page=2",
    "path": "http://api.example.com/api/catalog/products",
    "per_page": 20,
    "prev_page_url": null,
    "to": 20,
    "total": 95
  }
}
```

**Notes:**
- Images are provided in 4 sizes: `sm` (small), `md` (medium), `lg` (large), `original`
- `min_price` and `max_price` reflect variant pricing if variants exist
- Variants and detailed files are NOT included in list view (use detail endpoint)
- All image URLs are permanent S3 URLs (no temporary signatures)

---

### 3. Get Product Details

Retrieve detailed information about a single product, including variants and all images.

**Endpoint:** `GET /api/catalog/products/{slug_or_id}`

**Headers:**
```
X-Company-Hash: your-company-hash
```

**Path Parameters:**
- `slug_or_id`: Product slug (e.g., `running-shoes`) OR numeric ID (e.g., `1008`)

**Examples:**
- By slug: `GET /api/catalog/products/running-shoes`
- By ID: `GET /api/catalog/products/1008`

**Response:**
```json
{
  "status": "success",
  "message": "Product fetched",
  "product": {
    "id": 1008,
    "name": "Running Shoes",
    "slug": "running-shoes",
    "short_description": "Comfortable running shoes for daily use",
    "description": "<p>Detailed product description with HTML formatting...</p>",
    "specifications": "<ul><li>Material: Synthetic</li><li>Weight: 250g</li></ul>",
    "product_type": "Physical",
    "price": 100,
    "taxes": "10",
    "payment_type": "OneTime",
    "payment_frequency": "Week",
    "recurring_repeat": 1,
    "is_featured": false,
    "sku": "SKU-SHOES-001",
    "stock": 50,
    "min_price": 80,
    "max_price": 120,
    "views": 150,
    "packaging": {
      "length": 30,
      "width": 20,
      "height": 10,
      "dimensions_unit": "cm",
      "weight": 0.5,
      "weight_unit": "kg"
    },
    "images": [
      {
        "id": null,
        "filename": "main-image.jpg",
        "is_default": true,
        "position": 0,
        "urls": {
          "sm": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/sm_main-image.jpg",
          "md": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/md_main-image.jpg",
          "lg": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/lg_main-image.jpg",
          "original": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/main-image.jpg"
        }
      },
      {
        "id": 123,
        "filename": "side-view.jpg",
        "is_default": false,
        "position": 1,
        "urls": {
          "sm": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/sm_abc123.jpg",
          "md": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/md_abc123.jpg",
          "lg": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/lg_abc123.jpg",
          "original": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/abc123.jpg"
        }
      }
    ],
    "categories": [
      {
        "id": 5,
        "category_name": "Footwear",
        "slug": "footwear",
        "parent_id": null
      }
    ],
    "variants": [
      {
        "id": 1,
        "product_id": 1008,
        "name": "Red - Size 10",
        "price": 120,
        "stock": 15,
        "sku": "SKU-SHOES-RED-10",
        "is_default": true,
        "images": [
          {
            "id": 456,
            "filename": "red-variant.jpg",
            "position": 1,
            "urls": {
              "sm": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/sm_def456.jpg",
              "md": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/md_def456.jpg",
              "lg": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/lg_def456.jpg",
              "original": "https://missiov2.s3.us-east-2.amazonaws.com/user-uploads/10/products/1008/def456.jpg"
            }
          }
        ],
        "created_at": "2024-01-01T00:00:00.000000Z",
        "updated_at": "2024-01-08T17:00:00.000000Z"
      },
      {
        "id": 2,
        "product_id": 1008,
        "name": "Blue - Size 10",
        "price": 100,
        "stock": 25,
        "sku": "SKU-SHOES-BLUE-10",
        "is_default": false,
        "images": [],
        "created_at": "2024-01-01T00:00:00.000000Z",
        "updated_at": "2024-01-08T17:00:00.000000Z"
      }
    ],
    "created_at": "2024-01-01T00:00:00.000000Z",
    "updated_at": "2024-01-08T17:00:00.000000Z"
  }
}
```

**Notes:**
- The `images` array includes the default image (position 0, `is_default: true`) followed by additional images
- Each image includes 4 size variants: `sm`, `md`, `lg`, `original`
- Variants include their own images array (may be empty)
- All image URLs are permanent S3 URLs without temporary signatures
- Product lookup works with both slug and numeric ID

---

## Error Responses

### Missing Company Hash (422)
```json
{
  "status": "error",
  "message": "Missing or invalid X-Company-Hash header."
}
```

### Product Not Found (404)
```json
{
  "status": "error",
  "message": "Product not found"
}
```

---

## Image Sizes

All product and category images are available in multiple sizes for responsive design:

| Size | Prefix | Typical Use |
|------|--------|-------------|
| Small | `sm_` | Thumbnails, list views on mobile (480w) |
| Medium | `md_` | Grid views, tablets (800w) |
| Large | `lg_` | Detail pages, hero images (1200w+) |
| Original | none | Full resolution, zoom features |

**Example:**
```
sm_ddbe21380d62aa1c288a270993035f48.jpg  // Small
md_ddbe21380d62aa1c288a270993035f48.jpg  // Medium
lg_ddbe21380d62aa1c288a270993035f48.jpg  // Large
ddbe21380d62aa1c288a270993035f48.jpg     // Original
```

---

## Common Use Cases

### 1. Display Category Menu
```javascript
fetch('https://adminv2.missio.io/api/catalog/categories', {
  headers: {
    'X-Company-Hash': 'your-company-hash'
  }
})
.then(res => res.json())
.then(data => {
  console.log(data.categories); // Render category tree
});
```

### 2. Product Listing with Search and Filter
```javascript
const params = new URLSearchParams({
  search: 'shoes',
  category_slug: 'footwear',
  min_price: 50,
  max_price: 200,
  sort: 'price',
  per_page: 20,
  page: 1
});

fetch(`https://adminv2.missio.io/api/catalog/products?${params}`, {
  headers: {
    'X-Company-Hash': 'your-company-hash'
  }
})
.then(res => res.json())
.then(data => {
  console.log(data.products.data); // Display products
  console.log(data.products.total); // Total count
});
```

### 3. Product Detail Page
```javascript
// By slug
fetch('https://adminv2.missio.io/api/catalog/products/running-shoes', {
  headers: {
    'X-Company-Hash': 'your-company-hash'
  }
})
.then(res => res.json())
.then(data => {
  console.log(data.product); // Full product details
  console.log(data.product.images); // All images
  console.log(data.product.variants); // Product variants
});

// Or by ID
fetch('https://adminv2.missio.io/api/catalog/products/1008', {
  headers: {
    'X-Company-Hash': 'your-company-hash'
  }
});
```

---

## Best Practices

1. **Image Loading:**
   - Use `sm` images for thumbnails and mobile list views
   - Use `md` images for grid layouts on tablets
   - Use `lg` images for product detail pages
   - Use `original` for zoom/lightbox features

2. **Caching:**
   - Cache category tree (changes infrequently)
   - Cache product lists with appropriate TTL
   - Image URLs are permanent and can be cached indefinitely

3. **Pagination:**
   - Use `per_page` parameter to control response size
   - Start with smaller page sizes (20) for better performance
   - Maximum `per_page` is 100

4. **Search Performance:**
   - Combine search with category filters for better results
   - Use price range filters to narrow results
   - Sort by `popularity` to show most-viewed items first

5. **Variants:**
   - Display variant count on product cards
   - Show price range (min_price to max_price) when variants exist
   - Load variant details only on product detail page

---

## Testing

Use the provided Postman collection: `postman/Missio-Shop-API.postman_collection.json`

**Steps:**
1. Import the collection into Postman
2. Set collection variables:
   - `base_url`: Your API base URL
   - `c_hash`: Your company hash from the database
3. Run the "Catalog" folder requests

---

## Support

For issues or questions:
- Check error responses for detailed messages
- Verify `X-Company-Hash` header is correct
- Ensure products have `status = 1` (active)
- Confirm company exists and is active
