Shop It Docs
Developer ResourcescatalogBrand Series

Brand Series Module API & Integration Guide

HTTP contract reference for catalog brand-series admin and customer/mobile APIs.

Audience: Mobile/web frontend developers, admin panel developers Scope: Brand series management, storefront series listing and detail

Brand Series Module - API & Integration Guide

1. How to Read / Quick Metadata

  • Module: BrandSeries
  • Auth models:
    • Customer/mobile routes: Public (no authentication required)
    • Admin routes: JwtAuthGuard + RoleGuard + @Permissions(...)
  • Primary base URLs:
    • Admin: /api/admin/brand-series
    • Customer: /api/brand-series
    • Mobile-composed customer: /api/mobile/brand-series
  • Response envelope: successful endpoints return ResponseDto<T>
  • Swagger tags used by controllers:
    • Brand Series (Admin)
    • Brand Series

2. High-Level Overview

Brand Series API is split into:

  • admin CRUD endpoints for series management (create, read, update, delete, reorder)
  • public read-only endpoints for storefront listing and detail

Admin endpoints require specific BrandSeries_* permissions and are used by the admin panel. Customer endpoints are public and return only visible (isActive = true) series.

Mobile-composed endpoints mirror customer endpoints exactly and are available under /api/mobile/brand-series/... via MobileModule routing composition.

3. Core Concepts and Terminology

  • brand series: a named collection of products within a brand, scoped to a category (e.g. "Dell XPS Series" under Brand "Dell" and Category "Laptops"). Stored in the brand_series table.
  • slug: URL-safe identifier auto-generated from series name with suffix resolution on conflict. Used as the lookup key for public detail endpoints.
  • visibility: isActive boolean controls whether a series appears in public endpoints. Admin endpoints always return all series regardless of visibility.
  • order: integer field for manual storefront sequencing. Lower values appear first. Default sort is order ASC, name ASC.
  • product count: count of published and sellable products linked to this series via product.series_id. Only available in customer detail endpoint.
  • reorder: bulk update operation that accepts an array of { id, order } tuples to set the display order for multiple series at once.

Current admin operations:

  • List, Detail, Create, Update, Delete, Reorder

Current customer operations:

  • List (with brandId/categoryId filters), Detail by slug

4. Route Summary

4.1 Admin

MethodPathPermission
GET/api/admin/brand-seriesBrandSeries_READ
GET/api/admin/brand-series/:idBrandSeries_READ
POST/api/admin/brand-seriesBrandSeries_CREATE
PATCH/api/admin/brand-series/:idBrandSeries_UPDATE
PUT/api/admin/brand-series/reorderBrandSeries_UPDATE
DELETE/api/admin/brand-series/:idBrandSeries_DELETE

4.2 Customer / Mobile

MethodPathVisibility filter
GET/api/brand-seriesisActive = true
GET/api/brand-series/:slugisActive = true

Mobile-composed equivalents are available under /api/mobile/brand-series/....

5. Route Details

5.1 Admin List

AspectDetails
EndpointGET /api/admin/brand-series
AuthJwtAuthGuard + RoleGuard + BrandSeries_READ
Request queryFetchBrandSeriesAdminDto (extends QueryDto)
ResponseResponseDto<BrandSeriesAdminResponseDto[]> (paginated)
Errors403 insufficient permissions

Supports filtering by brandId, categoryId, and isActive as query parameters.

5.2 Admin Detail

AspectDetails
EndpointGET /api/admin/brand-series/:id
AuthJwtAuthGuard + RoleGuard + BrandSeries_READ
Requestpath: id (int)
ResponseResponseDto<BrandSeriesAdminResponseDto>
Errors404 BRAND_SERIES_NOT_FOUND

5.3 Admin Create

AspectDetails
EndpointPOST /api/admin/brand-series
AuthJwtAuthGuard + RoleGuard + BrandSeries_CREATE
Request bodyCreateBrandSeriesDto
ResponseResponseDto<BrandSeriesAdminResponseDto>
Errors404 BRAND_NOT_FOUND / CATEGORY_NOT_FOUND, 409 BRAND_SERIES_DUPLICATE

Validates brand and category existence before creating. Auto-generates slug from name with suffix resolution on conflict.

5.4 Admin Update

AspectDetails
EndpointPATCH /api/admin/brand-series/:id
AuthJwtAuthGuard + RoleGuard + BrandSeries_UPDATE
Requestpath: id (int), body: UpdateBrandSeriesDto
ResponseResponseDto<BrandSeriesAdminResponseDto>
Errors404 BRAND_SERIES_NOT_FOUND, 409 BRAND_SERIES_DUPLICATE

Partial update. If name changes, slug is regenerated and old+new detail cache is invalidated.

5.5 Admin Reorder

AspectDetails
EndpointPUT /api/admin/brand-series/reorder
AuthJwtAuthGuard + RoleGuard + BrandSeries_UPDATE
Request bodyReorderBrandSeriesDto { items: [{ id: number, order: number }] }
ResponseResponseDto (no data payload)
Errors-

Updates each item's order field individually. Invalidates list cache on completion.

5.6 Admin Delete

AspectDetails
EndpointDELETE /api/admin/brand-series/:id
AuthJwtAuthGuard + RoleGuard + BrandSeries_DELETE
Requestpath: id (int)
ResponseResponseDto<BrandSeriesAdminResponseDto>
Errors404 BRAND_SERIES_NOT_FOUND

Returns the deleted series data. Invalidates list and detail cache.

5.7 Customer List

AspectDetails
EndpointGET /api/brand-series or /api/mobile/brand-series
AuthPublic
Request queryFetchBrandSeriesDto (extends QueryDto)
ResponseResponseDto<BrandSeriesListItemDto[]> (paginated)
Errors-

Only returns series where isActive = true. Supports brandId and categoryId query filters.

5.8 Customer Detail

AspectDetails
EndpointGET /api/brand-series/:slug or /api/mobile/brand-series/:slug
AuthPublic
Requestpath: slug (string)
ResponseResponseDto<BrandSeriesDetailDto>
Errors404 BRAND_SERIES_NOT_FOUND

Includes productCount — number of published and sellable products linked to this series.

6. Query Parameters

6.1 Admin list (GET /api/admin/brand-series)

ParamTypeDefaultDescription
pagenumber1Page number (1-indexed)
sizenumber20Items per page (max 100)
paginationbooleantrueEnable/disable pagination
sortstringupdatedAtSort field
orderasc | descdescSort direction
searchstringoptionalText search
brandIdnumberoptionalFilter by brand id
categoryIdnumberoptionalFilter by category id
isActivebooleanoptionalFilter by visibility status

6.2 Customer list (GET /api/brand-series)

ParamTypeDefaultDescription
pagenumber1Page number (1-indexed)
sizenumber20Items per page (max 100)
paginationbooleantrueEnable/disable pagination
sortstringupdatedAtSort field
orderasc | descdescSort direction
searchstringoptionalText search
brandIdnumberoptionalFilter by brand id
categoryIdnumberoptionalFilter by category id

Note: Customer list endpoint always applies isActive = true as a hard filter regardless of query params. The service-level default sort is order ASC, name ASC (hardcoded in both admin and customer service).

7. Response Shape Examples

7.1 List item (admin or customer)

{
  "id": 1,
  "brandId": 3,
  "brandName": "Dell",
  "brandSlug": "dell",
  "categoryId": 5,
  "categoryName": "Laptops",
  "categorySlug": "laptops",
  "name": "Dell Laptops",
  "slug": "dell-laptops",
  "description": "Premium Dell laptop collection",
  "imageUrl": "https://cdn.example.com/dell-laptops.jpg",
  "isActive": true,
  "order": 0,
  "createdAt": "2026-06-09T10:00:00.000Z"
}

7.2 Customer detail (includes productCount)

{
  "id": 1,
  "brandId": 3,
  "brandName": "Dell",
  "brandSlug": "dell",
  "categoryId": 5,
  "categoryName": "Laptops",
  "categorySlug": "laptops",
  "name": "Dell Laptops",
  "slug": "dell-laptops",
  "description": "Premium Dell laptop collection",
  "imageUrl": "https://cdn.example.com/dell-laptops.jpg",
  "isActive": true,
  "order": 0,
  "createdAt": "2026-06-09T10:00:00.000Z",
  "productCount": 12
}

7.3 Create request payload

{
  "brandId": 3,
  "categoryId": 5,
  "name": "Dell Laptops",
  "description": "Premium Dell laptop collection",
  "imageUrl": "https://cdn.example.com/dell-laptops.jpg",
  "isActive": true,
  "order": 0
}

7.4 Update request payload (partial)

{
  "name": "Dell Premium Laptops",
  "isActive": false
}

7.5 Reorder request payload

{
  "items": [
    { "id": 1, "order": 0 },
    { "id": 2, "order": 1 },
    { "id": 3, "order": 2 }
  ]
}

7.6 Admin response (after create/update)

{
  "success": true,
  "message": "Brand series created successfully",
  "data": {
    "id": 1,
    "brandId": 3,
    "brandName": "Dell",
    "brandSlug": "dell",
    "categoryId": 5,
    "categoryName": "Laptops",
    "categorySlug": "laptops",
    "name": "Dell Laptops",
    "slug": "dell-laptops",
    "description": "Premium Dell laptop collection",
    "imageUrl": "https://cdn.example.com/dell-laptops.jpg",
    "isActive": true,
    "order": 0,
    "createdAt": "2026-06-09T10:00:00.000Z",
    "updatedAt": "2026-06-09T10:00:00.000Z"
  }
}

7.7 Paginated list response

{
  "success": true,
  "message": "Brand series fetched successfully",
  "data": [
    { "id": 1, "brandId": 3, "name": "Dell Laptops", "slug": "dell-laptops", ... },
    { "id": 2, "brandId": 3, "name": "Dell XPS", "slug": "dell-xps", ... }
  ],
  "meta": {
    "count": 5,
    "page": 1,
    "size": 20
  }
}

8. Enums

8.1 Sort fields

Brand series uses the QueryDto base sort field. Both admin and customer lists accept any valid column name as the sort parameter:

  • updatedAt (default)
  • name
  • order
  • createdAt
  • brandId
  • categoryId

The order parameter accepts:

  • asc (ascending)
  • desc (descending, default)

Note: The service layer hardcodes order ASC, name ASC for the query regardless of the sort/order query parameters. The QueryDto sort/order parameters are parsed but not currently applied to the DB query. This is the current implementation behavior.

9. Integration Diagram

10. Caching

Cache keyspaces:

  • catalog:brand-series:list:* - customer list responses
  • catalog:brand-series:detail:slug:* - customer detail by slug

TTL env:

  • CATALOG_CACHE_TTL_SECONDS (default 300)

Invalidation triggers:

  • admin write operations (create, update, delete, reorder) invalidate list cache via pattern
  • update and delete additionally invalidate the affected detail cache by slug
  • slug changes during update invalidate both old and new slug cache keys

11. Endpoint Reference + Payload Cheatsheet

11.1 Payload Cheatsheet Table (Every Endpoint)

MethodPathAuth / PermissionRequest DTO / ParamsSuccess DTONotes
GET/api/admin/brand-seriesAdmin + BrandSeries_READFetchBrandSeriesAdminDto (page?, size?, pagination?, brandId?, categoryId?, isActive?, sort?, order?, search?)BrandSeriesAdminResponseDto[] paginatedList all series; supports brand/category/visibility filters
GET/api/admin/brand-series/:idAdmin + BrandSeries_READpath: id (int)BrandSeriesAdminResponseDtoFetches single series by id
POST/api/admin/brand-seriesAdmin + BrandSeries_CREATECreateBrandSeriesDtoBrandSeriesAdminResponseDtoCreates series with auto-generated slug
PATCH/api/admin/brand-series/:idAdmin + BrandSeries_UPDATEpath: id (int), body: UpdateBrandSeriesDtoBrandSeriesAdminResponseDtoPartial update; regenerates slug if name changes
PUT/api/admin/brand-series/reorderAdmin + BrandSeries_UPDATEReorderBrandSeriesDto ({ items: [{ id: number, order: number }] })ResponseDto (no data)Bulk update order values; invalidates list cache
DELETE/api/admin/brand-series/:idAdmin + BrandSeries_DELETEpath: id (int)BrandSeriesAdminResponseDtoDeletes series; returns deleted data
GET/api/brand-seriesPublicFetchBrandSeriesDto (page?, size?, pagination?, brandId?, categoryId?, sort?, order?, search?)BrandSeriesListItemDto[] paginatedVisible series only; supports brand/category filters
GET/api/brand-series/:slugPublicpath: slug (string)BrandSeriesDetailDtoVisible series only; includes productCount

11.1.1 Admin List Endpoint Query Variations

MethodPathQuery ParametersNotes
GET/api/admin/brand-series(no params)Default: page=1, size=20, sort=updatedAt, order=desc
GET/api/admin/brand-series?page=2&size=10Custom page and size
GET/api/admin/brand-series?brandId=3Filter by brand
GET/api/admin/brand-series?categoryId=5Filter by category
GET/api/admin/brand-series?brandId=3&categoryId=5Filter by brand + category
GET/api/admin/brand-series?isActive=trueFilter by active series only
GET/api/admin/brand-series?isActive=falseFilter by inactive series only
GET/api/admin/brand-series?search=DellSearch by name
GET/api/admin/brand-series?pagination=falseReturns all records (no pagination)

11.1.2 Customer/Mobile List Endpoint Query Variations

MethodPathQuery ParametersNotes
GET/api/brand-series(no params)Default: page=1, size=20; visible only
GET/api/brand-series?brandId=3Filter by brand
GET/api/brand-series?categoryId=5Filter by category
GET/api/brand-series?brandId=3&categoryId=5Filter by brand + category
GET/api/brand-series?page=1&size=5Custom pagination
GET/api/brand-series?search=ThinkPadSearch by name
GET/api/brand-series?pagination=falseReturns all visible records

11.1.3 Create Series Request Variations

MethodPathRequest BodyNotes
POST/api/admin/brand-series{ "brandId": 3, "categoryId": 5, "name": "Dell Laptops" }Minimal create; defaults: isActive=true, order=0
POST/api/admin/brand-series{ "brandId": 3, "categoryId": 5, "name": "Dell Laptops", "description": "Premium collection", "imageUrl": "https://cdn.example.com/img.jpg", "isActive": true, "order": 1 }Full create with all optional fields

11.1.4 Update Series Request Variations

MethodPathBodyNotes
PATCH/api/admin/brand-series/1{ "name": "Dell Premium Laptops" }Update name (slug regenerated)
PATCH/api/admin/brand-series/1{ "isActive": false }Toggle visibility
PATCH/api/admin/brand-series/1{ "description": null }Clear description
PATCH/api/admin/brand-series/1{ "order": 5 }Change display order
PATCH/api/admin/brand-series/1{ "categoryId": 10 }Reassign to different category

11.1.5 Error Response Variations

HTTPerrorCodeMessageScenario
404BRAND_SERIES_NOT_FOUNDBrand series not foundInvalid series id/slug
404BRAND_NOT_FOUNDBrand not found.Invalid brandId in create
404CATEGORY_NOT_FOUNDCategory not found.Invalid categoryId in create
409BRAND_SERIES_DUPLICATEA series for this brand and category already existsDuplicate (brandId, categoryId) pair
409BRAND_SERIES_SLUG_EXISTSBrand series slug already existsSlug collision (rare; slug generation is conflict-aware)
403-ForbiddenMissing required BrandSeries_* permission
429RATE_LIMIT_EXCEEDEDToo many requests. Please try again later.Rate limit hit (global admin throttle)

11.1.6 Cache Key Patterns

Cache KeyPatternTTL (seconds)Invalidation
Customer listcatalog:brand-series:list:brand:<brandId>-cat:<catId>-page:<page>-size:<size>300 (or CATALOG_CACHE_TTL_SECONDS)Any admin write (create, update, delete, reorder)
Customer detailcatalog:brand-series:detail:slug:<slug>300 (or CATALOG_CACHE_TTL_SECONDS)Series update or delete affecting this slug

11.1.7 DTO Field Reference

CreateBrandSeriesDto

FieldTypeRequiredValidationNotes
brandIdnumberYesMin(1)FK to brand.id; validated on write
categoryIdnumberYesMin(1)FK to categories.id; validated on write
namestringYes1-255 chars, trimmedDisplay name; slug auto-generated from this
descriptionstringNoMax 1000 chars, trimmedOptional description for storefront display
imageUrlstringNoValid URL with protocolOptional image URL for series card
isActivebooleanNo-Defaults to true
ordernumberNoMin(0)Defaults to 0

UpdateBrandSeriesDto

UpdateBrandSeriesDto extends PartialType(CreateBrandSeriesDto) -- all fields from CreateBrandSeriesDto are optional.

FieldTypeRequiredNotes
brandIdnumberNoWill re-validate brand if provided
categoryIdnumberNoWill re-validate category if provided
namestringNoSlug regenerated if changed
descriptionstringNoSet to null to clear
imageUrlstringNoSet to null to clear
isActivebooleanNoToggle visibility
ordernumberNoChange display order

ReorderBrandSeriesDto

FieldTypeRequiredValidationNotes
itemsReorderItemDto[]YesArray of objectsEach item must have id and order

ReorderItemDto

FieldTypeRequiredValidationNotes
idnumberYesMin(1)Series id to reorder
ordernumberYesMin(0)New order position

BrandSeriesAdminResponseDto

FieldTypeNotes
idnumberPrimary key
brandIdnumberFK to brand
brandNamestringResolved brand name (from DB join)
brandSlugstringResolved brand slug (from DB join)
categoryIdnumberFK to category
categoryNamestringResolved category name (from DB join)
categorySlugstringResolved category slug (from DB join)
namestringSeries display name
slugstringURL-safe identifier
descriptionstring | nullOptional description
imageUrlstring | nullOptional image URL
isActivebooleanVisibility flag
ordernumberDisplay order
createdAtDateCreation timestamp
updatedAtDateLast update timestamp

BrandSeriesListItemDto

Same as BrandSeriesAdminResponseDto without the updatedAt field.

BrandSeriesDetailDto

Extends BrandSeriesListItemDto with:

FieldTypeNotes
productCountnumberCount of published + sellable products linked to this series

12. Testing Scenarios

12.1 Admin Create Series

Test Case: Create a new brand series with valid brand and category

  1. Admin has BrandSeries_CREATE permission.
  2. POST /api/admin/brand-series with { "brandId": 3, "categoryId": 5, "name": "Dell Laptops" }.
  3. Expect 201 with BrandSeriesAdminResponseDto containing auto-generated slug.
  4. Verify slug is dell-laptops.
  5. Verify isActive defaults to true.
  6. Verify order defaults to 0.

12.2 Admin Create Duplicate Series

Test Case: Create series with duplicate brand-category pair

  1. Series for brand 3 and category 5 already exists.
  2. POST /api/admin/brand-series with { "brandId": 3, "categoryId": 5, "name": "Another Series" }.
  3. Expect 409 with errorCode: "BRAND_SERIES_DUPLICATE".

12.3 Admin Update Series Name

Test Case: Update series name triggers slug regeneration

  1. Series exists with slug dell-laptops.
  2. PATCH /api/admin/brand-series/1 with { "name": "Dell Premium Laptops" }.
  3. Expect 200 with updated slug dell-premium-laptops.
  4. Verify old cache key catalog:brand-series:detail:slug:dell-laptops is invalidated.
  5. Verify new cache key catalog:brand-series:detail:slug:dell-premium-laptops is populated on next read.

12.4 Admin Reorder Series

Test Case: Reorder multiple series at once

  1. Three series exist with orders 0, 1, 2.
  2. PUT /api/admin/brand-series/reorder with { "items": [{ "id": 3, "order": 0 }, { "id": 1, "order": 1 }, { "id": 2, "order": 2 }] }.
  3. Expect 200 with success message.
  4. Verify GET list returns series in the new order.

12.5 Customer List Series by Brand

Test Case: List visible series for a specific brand

  1. Brand 3 has 5 series, 3 of which are active.
  2. GET /api/brand-series?brandId=3.
  3. Expect 200 with paginated list of 3 active series.
  4. Verify all items have isActive = true.
  5. Verify pagination meta is accurate.

12.6 Customer Detail by Slug

Test Case: Get series detail with product count

  1. Series "dell-laptops" exists with 12 published sellable products.
  2. GET /api/brand-series/dell-laptops.
  3. Expect 200 with BrandSeriesDetailDto.
  4. Verify slug is dell-laptops.
  5. Verify productCount is 12.

12.7 Customer Detail Not Found

Test Case: Request inactive series via customer endpoint

  1. Series exists with isActive = false and slug inactive-series.
  2. GET /api/brand-series/inactive-series.
  3. Expect 404 with errorCode: "BRAND_SERIES_NOT_FOUND".

13. Error Handling

All brand series API errors return the standard error envelope:

{
  "statusCode": 404,
  "errorCode": "BRAND_SERIES_NOT_FOUND",
  "message": "Brand series not found.",
  "timestamp": "2026-06-09T10:00:00.000Z",
  "path": "/api/brand-series/invalid-slug"
}

Representative error map:

HTTPerrorCodeMessage
404BRAND_SERIES_NOT_FOUNDBrand series not found.
404BRAND_NOT_FOUNDBrand not found.
404CATEGORY_NOT_FOUNDCategory not found.
409BRAND_SERIES_DUPLICATEA series for this brand and category already exists.
409BRAND_SERIES_SLUG_EXISTSBrand series slug already exists.
403-Forbidden resource.
429RATE_LIMIT_EXCEEDEDToo many requests. Please try again later.
503ERR_CONFIG_INVALIDConfiguration validation failed.

Time fields in this module are stored as timezone-aware values and should be handled as ISO-8601 instants by API consumers.


See Also

  • Feature Guide: See Brand Series - Feature List Section 6 (State Models) for lifecycle details.
  • Backend Reference: See Brand Series - Backend Documentation Section 3 (Data Model) for schema and indexes.
  • Brand Module: See /docs/developer/catalog/brand for brand-level API documentation.
  • Product Module: See /docs/developer/product for product-to-series linkage API.