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

# Brand API

> Create, update, delete, and manage optical brands with pagination, search, and filtering capabilities

# Brand API

The Brand API allows you to create, update, delete, and retrieve optical brands with advanced filtering, search, and pagination. Brands are associated with stores and can be searched and sorted by various criteria. The API supports bulk deletion operations and ensures brands are properly scoped to their respective stores.

## Endpoint Details

**Base URL:** `https://joptic.jethings.com`

### Required Headers

```
x-store-id: <store_id>
Authorization: Bearer <token>
```

***

## Create Brand

### Endpoint

**Endpoint:** `POST /brand`\
**Content-Type:** `application/json`

### Request Structure

The request body contains the brand name to create a new brand.

### Request Body

```json theme={null}
{
  "brandName": "Acme Optics"
}
```

### Request Body Fields

| Field       | Type   | Required | Description                 |
| ----------- | ------ | -------- | --------------------------- |
| `brandName` | string | ✅ Yes    | Name of the brand to create |

***

## Create Brand Examples

### Example 1: Create a New Brand

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://joptic.jethings.com/brand \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "brandName": "Acme Optics"
    }'
  ```

  ```javascript JavaScript theme={null}
  const brandData = {
    brandName: "Acme Optics",
  }

  const response = await fetch("https://joptic.jethings.com/brand", {
    method: "POST",
    headers: {
      "x-store-id": "your-store-id",
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(brandData),
  })

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

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

  url = "https://joptic.jethings.com/brand"

  brand_data = {
      "brandName": "Acme Optics"
  }

  response = requests.post(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      },
      json=brand_data
  )

  print(response.json())
  ```
</CodeGroup>

**Success Response:**

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Acme Optics",
  "createdAt": "2024-01-15T10:00:00.000Z",
  "updatedAt": "2024-01-15T10:00:00.000Z"
}
```

***

## Update Brand

### Endpoint

**Endpoint:** `PUT /brand/:id`\
**Content-Type:** `application/json`

### Path Parameters

| Parameter | Type   | Required | Description                 |
| --------- | ------ | -------- | --------------------------- |
| `id`      | string | ✅ Yes    | UUID of the brand to update |

### Request Structure

The request body contains optional fields to update the brand. Only provided fields will be updated.

### Request Body

```json theme={null}
{
  "brandName": "Updated Brand Name"
}
```

### Request Body Fields

| Field       | Type   | Required | Description                                 |
| ----------- | ------ | -------- | ------------------------------------------- |
| `brandName` | string | No       | New name for the brand (max 255 characters) |

<Note>
  The `brandName` field is optional. If not provided, the brand name will remain unchanged. Only fields that are explicitly provided will be updated.
</Note>

***

## Update Brand Examples

### Example 1: Update Brand Name

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT https://joptic.jethings.com/brand/550e8400-e29b-41d4-a716-446655440000 \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "brandName": "Updated Acme Optics"
    }'
  ```

  ```javascript JavaScript theme={null}
  const brandData = {
    brandName: "Updated Acme Optics",
  }

  const response = await fetch(
    "https://joptic.jethings.com/brand/550e8400-e29b-41d4-a716-446655440000",
    {
      method: "PUT",
      headers: {
        "x-store-id": "your-store-id",
        Authorization: "Bearer <token>",
        "Content-Type": "application/json",
      },
      body: JSON.stringify(brandData),
    },
  )

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

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

  url = "https://joptic.jethings.com/brand/550e8400-e29b-41d4-a716-446655440000"

  brand_data = {
      "brandName": "Updated Acme Optics"
  }

  response = requests.put(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      },
      json=brand_data
  )

  print(response.json())
  ```
</CodeGroup>

**Success Response:**

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Updated Acme Optics",
  "createdAt": "2024-01-15T10:00:00.000Z",
  "updatedAt": "2024-01-15T11:30:00.000Z"
}
```

***

## Delete Brands

### Endpoint

**Endpoint:** `DELETE /brand`\
**Content-Type:** `application/json`

### Request Structure

The request body contains an array of brand IDs to delete. This endpoint performs a bulk delete operation, removing the brand-store relationships (soft delete by setting `isActive` to false).

### Request Body

```json theme={null}
{
  "ids": [
    "550e8400-e29b-41d4-a716-446655440000",
    "660e8400-e29b-41d4-a716-446655440001"
  ]
}
```

### Request Body Fields

| Field | Type      | Required | Description                                        |
| ----- | --------- | -------- | -------------------------------------------------- |
| `ids` | string\[] | ✅ Yes    | Array of brand UUIDs to delete (must not be empty) |

<Warning>
  This operation performs a soft delete by deactivating the brand-store relationship. Brands are not permanently deleted from the database, but they will no longer appear in GET requests for the store.
</Warning>

***

## Delete Brands Examples

### Example 1: Delete Single Brand

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://joptic.jethings.com/brand \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "ids": ["550e8400-e29b-41d4-a716-446655440000"]
    }'
  ```

  ```javascript JavaScript theme={null}
  const deleteData = {
    ids: ["550e8400-e29b-41d4-a716-446655440000"],
  }

  const response = await fetch("https://joptic.jethings.com/brand", {
    method: "DELETE",
    headers: {
      "x-store-id": "your-store-id",
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(deleteData),
  })

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

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

  url = "https://joptic.jethings.com/brand"

  delete_data = {
      "ids": ["550e8400-e29b-41d4-a716-446655440000"]
  }

  response = requests.delete(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      },
      json=delete_data
  )

  print(response.json())
  ```
</CodeGroup>

**Success Response:**

```json theme={null}
{
  "message": "Successfully deleted 1 brand(s)",
  "deletedCount": 1
}
```

***

### Example 2: Bulk Delete Multiple Brands

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://joptic.jethings.com/brand \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "ids": [
        "550e8400-e29b-41d4-a716-446655440000",
        "660e8400-e29b-41d4-a716-446655440001",
        "770e8400-e29b-41d4-a716-446655440002"
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  const deleteData = {
    ids: [
      "550e8400-e29b-41d4-a716-446655440000",
      "660e8400-e29b-41d4-a716-446655440001",
      "770e8400-e29b-41d4-a716-446655440002",
    ],
  }

  const response = await fetch("https://joptic.jethings.com/brand", {
    method: "DELETE",
    headers: {
      "x-store-id": "your-store-id",
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(deleteData),
  })

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

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

  url = "https://joptic.jethings.com/brand"

  delete_data = {
      "ids": [
          "550e8400-e29b-41d4-a716-446655440000",
          "660e8400-e29b-41d4-a716-446655440001",
          "770e8400-e29b-41d4-a716-446655440002"
      ]
  }

  response = requests.delete(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      },
      json=delete_data
  )

  print(response.json())
  ```
</CodeGroup>

**Success Response:**

```json theme={null}
{
  "message": "Successfully deleted 3 brand(s)",
  "deletedCount": 3
}
```

***

## Get All Brands

### Endpoint

**Endpoint:** `GET /brand`

### Query Parameters

| Parameter   | Type   | Required | Default   | Description                                     |
| ----------- | ------ | -------- | --------- | ----------------------------------------------- |
| `search`    | string | No       | -         | Search brands by name (partial match)           |
| `page`      | number | No       | 1         | Page number for pagination                      |
| `limit`     | number | No       | 10        | Number of records per page                      |
| `sortBy`    | string | No       | createdAt | Sort field: "name", "createdAt", or "updatedAt" |
| `sortOrder` | string | No       | desc      | Sort order: "asc" or "desc"                     |

<Note>
  The `storeId` is automatically extracted from the `x-store-id` header and does not need to be provided as a query parameter.
</Note>

### Sort Options

The `sortBy` parameter accepts the following values:

* `"name"` - Sort by brand name alphabetically
* `"createdAt"` - Sort by creation date (default)
* `"updatedAt"` - Sort by last update date

***

## Get Brands Examples

### Example 1: Get All Brands (Default Pagination)

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://joptic.jethings.com/brand" \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://joptic.jethings.com/brand", {
    method: "GET",
    headers: {
      "x-store-id": "your-store-id",
      Authorization: "Bearer <token>",
    },
  })

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

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

  url = "https://joptic.jethings.com/brand"

  response = requests.get(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>"
      }
  )

  print(response.json())
  ```
</CodeGroup>

**Success Response:**

```json theme={null}
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Acme Optics",
      "createdAt": "2024-01-15T10:00:00.000Z",
      "updatedAt": "2024-01-15T10:00:00.000Z"
    },
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "name": "Vision Pro",
      "createdAt": "2024-01-14T09:00:00.000Z",
      "updatedAt": "2024-01-14T09:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 25,
    "totalPages": 3,
    "hasNext": true,
    "hasPrev": false
  }
}
```

***

### Example 2: Search Brands with Filters

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://joptic.jethings.com/brand?search=Acme&page=1&limit=20&sortBy=name&sortOrder=asc" \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({
    search: "Acme",
    page: "1",
    limit: "20",
    sortBy: "name",
    sortOrder: "asc",
  })

  const response = await fetch(`https://joptic.jethings.com/brand?${params}`, {
    method: "GET",
    headers: {
      "x-store-id": "your-store-id",
      Authorization: "Bearer <token>",
    },
  })

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

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

  url = "https://joptic.jethings.com/brand"

  params = {
      "search": "Acme",
      "page": 1,
      "limit": 20,
      "sortBy": "name",
      "sortOrder": "asc"
  }

  response = requests.get(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>"
      },
      params=params
  )

  print(response.json())
  ```
</CodeGroup>

***

### Example 3: Get Brands Sorted by Update Date

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://joptic.jethings.com/brand?sortBy=updatedAt&sortOrder=desc" \
    -H "x-store-id: your-store-id" \
    -H "Authorization: Bearer <token>"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({
    sortBy: "updatedAt",
    sortOrder: "desc",
  })

  const response = await fetch(`https://joptic.jethings.com/brand?${params}`, {
    method: "GET",
    headers: {
      "x-store-id": "your-store-id",
      Authorization: "Bearer <token>",
    },
  })

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

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

  url = "https://joptic.jethings.com/brand"

  params = {
      "sortBy": "updatedAt",
      "sortOrder": "desc"
  }

  response = requests.get(
      url,
      headers={
          "x-store-id": "your-store-id",
          "Authorization": "Bearer <token>"
      },
      params=params
  )

  print(response.json())
  ```
</CodeGroup>

***

## Response Structures

### Create Brand Response

```json theme={null}
{
  "id": "string (UUID)",
  "name": "string",
  "createdAt": "ISO date string",
  "updatedAt": "ISO date string"
}
```

### Update Brand Response

```json theme={null}
{
  "id": "string (UUID)",
  "name": "string",
  "createdAt": "ISO date string",
  "updatedAt": "ISO date string"
}
```

### Delete Brands Response

```json theme={null}
{
  "message": "string",
  "deletedCount": "number"
}
```

### Get Brands Response

```json theme={null}
{
  "data": [
    {
      "id": "string (UUID)",
      "name": "string",
      "createdAt": "ISO date string",
      "updatedAt": "ISO date string"
    }
  ],
  "pagination": {
    "page": "number",
    "limit": "number",
    "total": "number",
    "totalPages": "number",
    "hasNext": "boolean",
    "hasPrev": "boolean"
  }
}
```

***

## Error Responses

### 400 Bad Request

```json theme={null}
{
  "statusCode": 400,
  "message": "brandName should not be empty",
  "error": "Bad Request"
}
```

Or for delete operations:

```json theme={null}
{
  "statusCode": 400,
  "message": "No brand IDs provided",
  "error": "Bad Request"
}
```

### 404 Not Found

```json theme={null}
{
  "statusCode": 404,
  "message": "Brand not found",
  "error": "Not Found"
}
```

Or for delete operations:

```json theme={null}
{
  "statusCode": 404,
  "message": "No valid brands found to delete",
  "error": "Not Found"
}
```

### 403 Forbidden

```json theme={null}
{
  "statusCode": 403,
  "message": "You do not have access to this store",
  "error": "Forbidden"
}
```

### 500 Internal Server Error

```json theme={null}
{
  "statusCode": 500,
  "message": "Failed to create brand",
  "error": "Internal Server Error"
}
```

***

## Important Notes

### Store Association

<AccordionGroup>
  <Accordion title="Brand-Store Relationship">
    * Brands are associated with stores through `brandStoreRelation`
    * Only brands with active store relations are returned in GET requests
    * The `storeId` parameter filters brands for the specified store
    * Brands must have `isActive: true` in the store relation to appear in results
    * When creating a brand, it's automatically associated with the store via `x-store-id` header
  </Accordion>

  <Accordion title="Store Access">
    * Requires user to have access to the store
    * Store access is validated via `x-store-id` header
    * Missing or invalid store access raises `ForbiddenException`
    * Update and delete operations verify that the brand belongs to the specified store
  </Accordion>

  <Accordion title="Update Operations">
    * Only brands that belong to the store (via active `brandStoreRelation`) can be updated
    * The brand must exist and have an active relationship with the store
    * If brand doesn't exist or doesn't belong to the store, a `NotFoundException` is raised
    * Only provided fields in the request body will be updated
    * The `updatedAt` timestamp is automatically updated
  </Accordion>

  <Accordion title="Delete Operations">
    * Delete operations perform a soft delete by setting `isActive: false` in `brandStoreRelation`
    * Only brands that belong to the store can be deleted
    * Invalid or non-existent brand IDs are filtered out before deletion
    * The response includes the count of successfully deleted brands
    * If no valid brands are found, a `NotFoundException` is raised
  </Accordion>
</AccordionGroup>

### Search Functionality

<CardGroup cols={2}>
  <Card title="Partial Match" icon="search">
    Search uses `LIKE` query with wildcards

    <br />

    <code>%searchTerm%</code>
  </Card>

  <Card title="Case Insensitive" icon="text">
    Search is case-insensitive

    <br />

    <code>Matches "acme", "Acme", "ACME"</code>
  </Card>
</CardGroup>

### Pagination

<Tabs>
  <Tab title="Default Behavior">
    ```javascript theme={null}
    {
      page: 1,
      limit: 10,
      sortBy: "createdAt",
      sortOrder: "desc"
    }
    ```

    Returns 10 most recent brands by default
  </Tab>

  <Tab title="Custom Pagination">
    ```javascript theme={null}
    {
      page: 2,
      limit: 50,
      sortBy: "name",
      sortOrder: "asc"
    }
    ```

    Customize page size and sorting
  </Tab>
</Tabs>

### Sorting Options

The API supports sorting by:

* **Name** (`sortBy=name`) - Alphabetical sorting
* **Created At** (`sortBy=createdAt`) - Creation timestamp (default)
* **Updated At** (`sortBy=updatedAt`) - Last update timestamp

Both ascending (`asc`) and descending (`desc`) orders are supported.

### Pagination Metadata

The pagination object includes:

* `page` - Current page number
* `limit` - Number of items per page
* `total` - Total number of brands matching the query
* `totalPages` - Total number of pages
* `hasNext` - Boolean indicating if there's a next page
* `hasPrev` - Boolean indicating if there's a previous page

***

## Summary

<Steps>
  <Step title="Authenticate">Obtain JWT token and ensure store access</Step>

  <Step title="Create Brand">
    POST request with brand name to create a new brand (automatically associated with store)
  </Step>

  <Step title="Retrieve Brands">
    GET request with optional filters, search, and pagination
  </Step>

  <Step title="Update Brand">
    PUT request with brand ID and optional brandName to update brand details
  </Step>

  <Step title="Delete Brands">
    DELETE request with array of brand IDs to bulk delete brands (soft delete)
  </Step>

  <Step title="Handle Response">
    Process brand data, pagination metadata, or deletion confirmation
  </Step>
</Steps>

This API provides comprehensive brand management for optical stores, including brand creation, updates, bulk deletion, flexible querying with search and filtering, and pagination capabilities.

***

<CardGroup cols={2}>
  <Card title="Item API" icon="package" href="/j-optic/item-api">
    Create and manage optical items
  </Card>

  <Card title="Customer API" icon="users" href="/j-optic/customer-api">
    Create and manage optical customers
  </Card>
</CardGroup>
