Skip to main content

Product Management

Author: Josh S. Sakweli, Backend Lead Team
Last Updated: 2026-05-19
Version: v2.01

Short Description: The Product Management API provides comprehensive functionality for managing products within shops on the NextGate platform. It supports group buying, installment payment plans, color variations, specifications, digital product file delivery, product preview media (video, PDF, 3D, image), and comprehensive search/filter capabilities with role-based access control.

Hints:


Endpoints

1. Create Product

Purpose: Creates a new product in a shop, supporting group buying, color variations, specifications, and digital product rules.

Endpoint: POST api/v1/e-commerce/shops/{shopId}/products

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token
Content-Type string Yes application/json

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop

Query Parameters:

Parameter Type Required Default Description
action ReqAction Yes SAVE_DRAFT or SAVE_PUBLISH

Request Body Parameters:

Parameter Type Required Description Validation
productType ProductType Yes PHYSICAL or DIGITAL Required
productName string Yes Unique name within shop Min: 2, Max: 100 chars
productDescription string Yes Detailed description Min: 10, Max: 1000 chars
price decimal Yes Selling price Min: 0.01, max 8 digits + 2 decimal places
stockQuantity integer Yes Available stock Min: 0
categoryId UUID Yes Product category Must exist and be active
comparePrice decimal No Original price for discount display Must be > price if provided
lowStockThreshold integer No Low stock alert threshold Min: 1, Max: 1000, Default: 5
condition ProductCondition No Product condition NEW, USED_LIKE_NEW, USED_GOOD, USED_FAIR, REFURBISHED, FOR_PARTS
status ProductStatus No Initial status (overridden by action) Default: ACTIVE
productImages array Yes Product image URLs Valid URLs, at least 1 required
specifications object No Key-value specs Key max 100 chars, Value max 500 chars
colors array No Color variations See Color object below
minOrderQuantity integer No Minimum order qty Min: 1, Default: 1
maxOrderQuantity integer No Maximum order qty per order Min: 1, must be ≥ minOrderQuantity
groupBuyingEnabled boolean No Enable group buying Default: false
groupMaxSize integer No Maximum group participants Min: 2, required if groupBuyingEnabled
groupPrice decimal No Discounted group price Must be < price
groupTimeLimitHours integer No Group formation time limit Min: 1, Max: 8760
downloadExpiryDays integer No Download link expiry (DIGITAL only) Min: 1, Default: 7
maxDownloadsPerBuyer integer No Download attempts per buyer (DIGITAL only) Min: 1
maxQuantityForDigital integer No Purchase cap per buyer (DIGITAL only) Min: 1

Color Object:

Field Type Required Validation
name string Yes Max: 50 chars
hex string Yes Valid #RRGGBB format
images array No Valid URLs
priceAdjustment decimal No Min: 0.0, Default: 0

Request JSON Sample (PHYSICAL):

{
  "productType": "PHYSICAL",
  "productName": "iPhone 15 Pro Max 256GB",
  "productDescription": "The most advanced iPhone featuring the A17 Pro chip and titanium design.",
  "price": 1199.00,
  "comparePrice": 1299.00,
  "stockQuantity": 25,
  "lowStockThreshold": 5,
  "categoryId": "123e4567-e89b-12d3-a456-426614174000",
  "condition": "NEW",
  "productImages": [
    "https://example.com/images/iphone15-main.jpg"
  ],
  "specifications": {
    "Display": "6.7-inch Super Retina XDR OLED",
    "Chip": "A17 Pro"
  },
  "colors": [
    {
      "name": "Natural Titanium",
      "hex": "#F5F5DC",
      "images": ["https://example.com/colors/natural-titanium.jpg"],
      "priceAdjustment": 0.00
    }
  ],
  "minOrderQuantity": 1,
  "maxOrderQuantity": 3,
  "groupBuyingEnabled": true,
  "groupMaxSize": 50,
  "groupPrice": 1099.00,
  "groupTimeLimitHours": 72
}

Request JSON Sample (DIGITAL):

{
  "productType": "DIGITAL",
  "productName": "UI Design Kit Pro",
  "productDescription": "A comprehensive Figma component library with 500+ components.",
  "price": 49.00,
  "stockQuantity": 1000,
  "categoryId": "123e4567-e89b-12d3-a456-426614174000",
  "productImages": ["https://example.com/images/design-kit-preview.jpg"],
  "downloadExpiryDays": 30,
  "maxDownloadsPerBuyer": 5,
  "maxQuantityForDigital": 1
}

Response JSON Sample:

{
  "success": true,
  "message": "Product created successfully",
  "data": null
}

Business Rules:

  • Product name must be unique within the shop
  • comparePrice must be greater than price
  • groupPrice must be less than price
  • All group buying settings (groupMaxSize, groupPrice, groupTimeLimitHours) required when groupBuyingEnabled=true
  • maxOrderQuantity must be ≥ minOrderQuantity
  • Digital download fields (downloadExpiryDays, maxDownloadsPerBuyer, maxQuantityForDigital) only apply to DIGITAL products
  • After creation, add installment plans via Installment Plan Config and digital files via Digital File Management

Error Responses:

  • 400: Validation errors or business rule violations
  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or category not found
  • 409: Product with same name already exists in shop
  • 422: Field-level validation errors

2. Update Product

Purpose: Updates an existing product. Only provided fields are updated.

Endpoint: PUT api/v1/e-commerce/shops/{shopId}/products/{productId}

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the product

Query Parameters:

Parameter Type Required Default Description
action ReqAction Yes SAVE_DRAFT or SAVE_PUBLISH

Request Body Parameters (all optional):

Parameter Type Description Validation
productName string Updated name Min: 2, Max: 100 chars
productDescription string Updated description Min: 10, Max: 1000 chars
price decimal Updated selling price Min: 0.01
comparePrice decimal Updated compare price Must be > price
stockQuantity integer Updated stock Min: 0
lowStockThreshold integer Updated low stock threshold Min: 1, Max: 1000
condition ProductCondition Updated condition See enum values
status ProductStatus Updated status Overridden by action
urgencyTag UrgencyTag Urgency badge on product NONE, NEW_ARRIVAL, LIMITED_EDITION, LIMITED_OFFER, FEW_REMAINS
categoryId UUID Updated category Must exist and be active
productImages array Updated image URLs Valid URLs, replaces existing
specifications object Updated specifications Completely replaces existing
colors array Updated color variations Completely replaces existing
minOrderQuantity integer Updated min order qty Min: 1
maxOrderQuantity integer Updated max order qty Min: 1, must be ≥ min
groupBuyingEnabled boolean Enable/disable group buying
groupMaxSize integer Updated group max Min: 2
groupPrice decimal Updated group price Must be < price
groupTimeLimitHours integer Updated group time limit Min: 1, Max: 8760
installmentEnabled boolean Enable/disable installment feature toggle
maxQuantityForInstallment integer Max qty a buyer can purchase on installment Min: 1
showStockAvailableToPublic boolean Show available stock count publicly
showSoldCountToPublic boolean Show sold count publicly
clearPreviewbooleanSet true to remove the product's preview file and type
previewDownloadablebooleanAllow/disallow viewers from downloading the preview file

Response JSON Sample:

{
  "success": true,
  "message": "Product updated successfully and published",
  "data": {
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "productName": "iPhone 15 Pro Max 512GB",
    "productSlug": "iphone-15-pro-max-512gb",
    "price": 1399.00,
    "status": "ACTIVE",
    "updatedAt": "2026-05-19T14:30:00Z"
  }
}

Error Responses:

  • 400: Invalid update data or validation errors
  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found
  • 409: Updated product name already exists

3. Publish Product

Purpose: Publishes a draft product making it active and publicly available.

Endpoint: PATCH api/v1/e-commerce/shops/{shopId}/products/{productId}/publish

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the draft product

Response JSON Sample:

{
  "success": true,
  "message": "Product 'iPhone 15 Pro Max' published successfully",
  "data": {
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "productName": "iPhone 15 Pro Max",
    "status": "ACTIVE",
    "publishedAt": "2026-05-19T14:45:00Z"
  }
}

Publishing Requirements:

  • Product name, description, price, stock quantity, category, and at least one image must be present
  • Group buying settings complete if enabled
  • Installment plans present if installment is enabled

Error Responses:

  • 400: Product already published or missing required publish fields
  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

4. Delete Product

Purpose: Deletes a product. Draft products are hard-deleted; published products are soft-deleted.

Endpoint: DELETE api/v1/e-commerce/shops/{shopId}/products/{productId}

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the product

Response JSON Sample (Soft Delete):

{
  "success": true,
  "message": "Product 'iPhone 15 Pro Max' has been deleted and will be permanently removed after 30 days",
  "data": {
    "productName": "iPhone 15 Pro Max",
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "previousStatus": "ACTIVE",
    "deletedAt": "2026-05-19T15:00:00Z",
    "deletionType": "SOFT_DELETE"
  }
}

Response JSON Sample (Hard Delete):

{
  "success": true,
  "message": "Draft product 'iPhone 15 Pro Max' has been permanently deleted",
  "data": null
}

Deletion Logic:

  • Draft products: Hard delete (permanently removed)
  • Published products: Soft delete (status → ARCHIVED, 30-day recovery window)

Error Responses:

  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

5. Restore Product

Purpose: Restores a soft-deleted product back to draft status.

Endpoint: PATCH api/v1/e-commerce/shops/{shopId}/products/{productId}/restore

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the soft-deleted product

Response JSON Sample:

{
  "success": true,
  "message": "Product 'iPhone 15 Pro Max' has been restored successfully",
  "data": {
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "productName": "iPhone 15 Pro Max",
    "status": "DRAFT",
    "restoredAt": "2026-05-19T15:30:00Z",
    "note": "Product restored as draft. Publish to make it active again."
  }
}

Error Responses:

  • 400: Product is not deleted
  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

6. Get Product Detailed (Owner/Admin View)

Purpose: Retrieves comprehensive product details including all management information.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/{productId}/detailed

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the product

Response JSON Sample:

{
  "success": true,
  "message": "Product details retrieved successfully",
  "data": {
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "productName": "iPhone 15 Pro Max 512GB",
    "productSlug": "iphone-15-pro-max-512gb",
    "productType": "PHYSICAL",
    "productDescription": "The most advanced iPhone ever...",
    "productImages": ["https://example.com/images/iphone15-main.jpg"],
    "price": 1199.00,
    "comparePrice": 1299.00,
    "discountAmount": 100.00,
    "discountPercentage": 7.69,
    "isOnSale": true,
    "stockQuantity": 25,
    "isInStock": true,
    "isLowStock": false,
    "sku": "SHP12345678-ELE-APP-512-0001",
    "condition": "NEW",
    "status": "ACTIVE",
    "urgencyTag": "NONE",
    "shopId": "123e4567-e89b-12d3-a456-426614174000",
    "shopName": "TechStore Pro",
    "categoryId": "789e0123-e89b-12d3-a456-426614174002",
    "categoryName": "Smartphones",
    "specifications": {
      "Display": "6.7-inch Super Retina XDR OLED",
      "Chip": "A17 Pro"
    },
    "colors": [
      {
        "name": "Natural Titanium",
        "hex": "#F5F5DC",
        "images": ["https://example.com/colors/natural-titanium.jpg"],
        "priceAdjustment": 0.00,
        "finalPrice": 1199.00
      }
    ],
    "groupBuying": {
      "isEnabled": true,
      "groupMaxSize": 50,
      "groupPrice": 1099.00,
      "timeLimitHours": 72
    },
    "installmentOptions": {
      "isEnabled": true,
      "plans": []
    },
    "previewType": "VIDEO",
    "previewUrl": "https://minio.example.com/nextgate-preview-content/preview/shop-id/product-id/uuid_trailer.mp4",
    "previewDownloadable": false,
    "createdAt": "2026-05-19T10:30:00Z",
    "updatedAt": "2026-05-19T14:30:00Z"
  }
}

Error Responses:

  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

7. Get Shop Products (Management View)

Purpose: Retrieves all products for a shop with summary statistics.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/all

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop

Response JSON Sample:

{
  "success": true,
  "message": "Retrieved 47 products from shop: TechStore Pro",
  "data": {
    "shop": {
      "shopId": "123e4567-e89b-12d3-a456-426614174000",
      "shopName": "TechStore Pro",
      "isVerified": true,
      "isMyShop": true
    },
    "summary": {
      "totalProducts": 47,
      "activeProducts": 35,
      "draftProducts": 8,
      "outOfStockProducts": 4,
      "lowStockProducts": 6,
      "productsWithGroupBuying": 18,
      "productsWithInstallments": 25
    },
    "products": [
      {
        "productId": "456e7890-e89b-12d3-a456-426614174001",
        "productName": "iPhone 15 Pro Max 512GB",
        "price": 1199.00,
        "stockQuantity": 25,
        "status": "ACTIVE",
        "isInStock": true,
        "hasGroupBuying": true,
        "hasInstallments": true,
        "createdAt": "2026-05-19T10:30:00Z"
      }
    ],
    "totalProducts": 47
  }
}

Error Responses:

  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop not found

8. Get Shop Products Paginated (Management View)

Purpose: Retrieves shop products with pagination for management dashboard.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/all-paged

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
size integer No 10 Items per page (max: 100)

Response JSON Sample:

{
  "success": true,
  "message": "Retrieved 10 products from shop: TechStore Pro (Page 1 of 5)",
  "data": {
    "contents": { "...same structure as /all..." },
    "currentPage": 1,
    "pageSize": 10,
    "totalElements": 47,
    "totalPages": 5,
    "hasNext": true,
    "hasPrevious": false
  }
}

Error Responses:

  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop not found

9. Get Public Product by ID

Purpose: Retrieves a single active product for public viewing.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/{productId}

Access Level: 🌐 Public

Path Parameters:

Parameter Type Required Description
shopId UUID Yes Shop must be active and approved
productId UUID Yes Product must be active

Response JSON Sample:

{
  "success": true,
  "message": "Product retrieved successfully",
  "data": {
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "productName": "iPhone 15 Pro Max 512GB",
    "productSlug": "iphone-15-pro-max-512gb",
    "productType": "PHYSICAL",
    "productDescription": "The most advanced iPhone ever...",
    "price": 1199.00,
    "comparePrice": 1299.00,
    "discountAmount": 100.00,
    "discountPercentage": 7.69,
    "isOnSale": true,
    "isInStock": true,
    "stockQuantity": 25,
    "condition": "NEW",
    "shopName": "TechStore Pro",
    "categoryName": "Smartphones",
    "specifications": { "Display": "6.7-inch OLED" },
    "colors": [
      {
        "name": "Natural Titanium",
        "hex": "#F5F5DC",
        "priceAdjustment": 0.00,
        "finalPrice": 1199.00
      }
    ],
    "groupBuying": {
      "isAvailable": true,
      "groupMaxSize": 50,
      "groupPrice": 1099.00,
      "timeLimitHours": 72
    },
    "installmentOptions": {
      "isAvailable": true,
      "plans": [
        {
          "planId": "...",
          "planName": "6-Month Interest-Free",
          "paymentFrequency": "MONTHLY",
          "numberOfPayments": 6,
          "apr": 0.00,
          "minDownPaymentPercent": 20
        }
      ]
    },
    "previewType": "PDF",
    "previewUrl": "https://minio.example.com/nextgate-preview-content/preview/shop-id/product-id/uuid_sample.pdf",
    "previewDownloadable": true,
    "createdAt": "2026-05-19T10:30:00Z"
  }
}

Notes:

  • previewType and previewUrl are null when no preview has been uploaded
  • Preview files are publicly accessible without authentication — the URL is permanent and direct

Error Responses:

  • 404: Shop not found/not approved, or product not found/not active

10. Get Public Shop Products

Purpose: Retrieves all active products from a shop for public browsing.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/public-view/all

Access Level: 🌐 Public

Path Parameters:

Parameter Type Required Description
shopId UUID Yes Shop must be active and approved

Response JSON Sample:

{
  "success": true,
  "message": "Retrieved 23 products from TechStore Pro",
  "data": {
    "shop": {
      "shopId": "123e4567-e89b-12d3-a456-426614174000",
      "shopName": "TechStore Pro",
      "isVerified": true
    },
    "products": [
      {
        "productId": "456e7890-e89b-12d3-a456-426614174001",
        "productName": "iPhone 15 Pro Max",
        "price": 1199.00,
        "isOnSale": true,
        "isInStock": true,
        "hasGroupBuying": true,
        "hasInstallments": true
      }
    ],
    "totalProducts": 23
  }
}

Error Responses:

  • 404: Shop not found, not approved, or not active

11. Get Public Shop Products Paginated

Purpose: Retrieves active products from a shop with pagination for public browsing.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/public-view/all-paged

Access Level: 🌐 Public

Path Parameters:

Parameter Type Required Description
shopId UUID Yes Shop must be active and approved

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
size integer No 10 Items per page (max: 50)

Error Responses:

  • 404: Shop not found, not approved, or not active

12. Search Products

Purpose: Searches products within a shop using multi-word query matching across multiple fields.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/search

Access Level: 🌐 Public (Enhanced features for authenticated users)

Authentication: Optional Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop

Query Parameters:

Parameter Type Required Default Description
q string Yes Search query (min: 2, max: 100 chars)
status ProductStatus[] No ACTIVE Statuses to search (owners/admins only for non-ACTIVE)
page integer No 1 Page number
size integer No 10 Items per page (max: 50)
sortBy string No relevance relevance, createdAt, updatedAt, productName, price, stockQuantity, brand
sortDir string No desc asc or desc

Search Behavior:

Feature Description
Multi-word Searches for products containing ALL words
Partial match "iph" matches "iPhone"
Cross-field Matches against name, description, brand, tags, specifications
Case-insensitive "APPLE" matches "apple"

User Access:

User Type Searchable Statuses
Public / Authenticated ACTIVE only
Shop Owner / Admin All statuses

Response JSON Sample:

{
  "success": true,
  "message": "Found 12 products matching 'iphone'",
  "data": {
    "contents": {
      "shop": { "shopId": "...", "shopName": "TechStore Pro" },
      "products": [ { "...product summary fields..." } ],
      "totalProducts": 12,
      "searchMetadata": {
        "searchQuery": "iphone",
        "searchedStatuses": ["ACTIVE"],
        "userType": "PUBLIC"
      }
    },
    "currentPage": 1,
    "pageSize": 10,
    "totalElements": 12,
    "totalPages": 2,
    "hasNext": true,
    "hasPrevious": false
  }
}

Error Responses:

  • 400: Query too short or too long
  • 404: Shop not found or not accessible

13. Advanced Product Filter

Purpose: Filters products using multiple criteria with combined AND/OR logic.

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/advanced-filter

Access Level: 🌐 Public (Enhanced features for authenticated users)

Authentication: Optional Bearer Token

Path Parameters:

Parameter Type Required Description
shopId UUID Yes ID of the shop

Query Parameters:

Parameter Type Required Default Description
minPrice decimal No Minimum price
maxPrice decimal No Maximum price (must be ≥ minPrice)
condition ProductCondition No Condition filter
categoryId UUID No Category filter
inStock boolean No Filter by availability
onSale boolean No Filter by sale status
hasGroupBuying boolean No Filter by group buying
hasInstallments boolean No Filter by installments
hasMultipleColors boolean No Filter by color variations
status ProductStatus[] No ACTIVE Status filter (owners/admins for non-ACTIVE)
page integer No 1 Page number
size integer No 10 Items per page (max: 50)
sortBy string No createdAt createdAt, updatedAt, productName, price, stockQuantity
sortDir string No desc asc or desc

Filter Logic:

Filter Type Logic
Price range AND (minPrice AND maxPrice)
Feature flags AND (all must match)
Multiple statuses OR

Error Responses:

  • 400: Invalid filter values or price range error
  • 404: Shop or category not found

14. Get Public Product by Slug

Purpose: Retrieves a single active product by its slug (same response shape as Get Public Product by ID).

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/find-by-slug/{slug}

Access Level: 🌐 Public

Path Parameters:

Parameter Type Required Description
shopId UUID Yes Shop must be active and approved
slug string Yes Product slug

Error Responses:

  • 404: Shop not found/not approved, or product not found/not active

15. Installment Plan Config

Purpose: CRUD for installment plans attached to a product. Plans are created separately after the product, and linked to it by productId.

Base URL: api/v1/e-commerce/products/{shopId}/{productId}/installment-plans

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters (shared):

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the product

15a. Create Installment Plan

Endpoint: POST api/v1/e-commerce/products/{shopId}/{productId}/installment-plans

Request Body:

Parameter Type Required Description Validation
planName string Yes Display name for the plan Min: 3, Max: 100 chars
paymentFrequency PaymentFrequency Yes Payment interval DAILY, WEEKLY, BI_WEEKLY, SEMI_MONTHLY, MONTHLY, QUARTERLY, CUSTOM_DAYS
customFrequencyDays integer Conditional Days between payments Required when paymentFrequency=CUSTOM_DAYS, min: 1
numberOfPayments integer Yes Total number of payments Min: 2, Max: 120
apr decimal Yes Annual percentage rate Min: 0.0, Max: 36.0, 2 decimal places
minDownPaymentPercent integer Yes Minimum down payment % Min: 10, Max: 50
fulfillmentTiming FulfillmentTiming Yes When to ship IMMEDIATE (ship after down payment), AFTER_PAYMENT (layaway — ship after final payment)
displayOrder integer No Sort order in UI Min: 0, Default: 0
isFeatured boolean No Highlight as recommended plan Default: false
isActive boolean No Plan is available to buyers Default: true

Request JSON Sample:

{
  "planName": "6-Month Interest-Free",
  "paymentFrequency": "MONTHLY",
  "numberOfPayments": 6,
  "apr": 0.00,
  "minDownPaymentPercent": 20,
  "fulfillmentTiming": "IMMEDIATE",
  "displayOrder": 1,
  "isFeatured": true,
  "isActive": true
}

Error Responses:

  • 400: Validation errors
  • 404: Shop or product not found

15b. Get All Installment Plans

Endpoint: GET api/v1/e-commerce/products/{shopId}/{productId}/installment-plans

Returns a list of all installment plans for the product.

Error Responses:

  • 404: Shop or product not found

15c. Get Installment Plan by ID

Endpoint: GET api/v1/e-commerce/products/{shopId}/{productId}/installment-plans/{planId}

Additional Path Parameter:

Parameter Type Description
planId UUID ID of the installment plan

15d. Update Installment Plan

Endpoint: PUT api/v1/e-commerce/products/{shopId}/{productId}/installment-plans/{planId}

All fields are optional — only provided fields are updated. Same field structure as Create.


15e. Delete Installment Plan

Endpoint: DELETE api/v1/e-commerce/products/{shopId}/{productId}/installment-plans/{planId}


15f. Activate / Deactivate Plan

Activate: PATCH api/v1/e-commerce/products/{shopId}/{productId}/installment-plans/{planId}/activate

Deactivate: PATCH api/v1/e-commerce/products/{shopId}/{productId}/installment-plans/{planId}/deactivate

Toggles isActive on the plan without changing any other fields.


Endpoint: PATCH api/v1/e-commerce/products/{shopId}/{productId}/installment-plans/{planId}/set-featured

Marks the specified plan as the featured (recommended) plan for this product.


16. Digital File Management

Purpose: Manages downloadable files for DIGITAL products. Uses a presign → upload → confirm flow to upload files directly to object storage.

Base URL: api/v1/e-commerce/shops/{shopId}/products/{productId}/digital-files

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters (shared):

Parameter Type Required Description
shopId UUID Yes ID of the shop
productId UUID Yes ID of the digital product

16a. Presign Upload

Purpose: Generates a presigned PUT URL. The client uploads the file directly to this URL, then calls /confirm.

Endpoint: POST api/v1/e-commerce/shops/{shopId}/products/{productId}/digital-files/presign-upload

Request Body:

Parameter Type Required Description
fileName string Yes Original file name
contentType string Yes MIME type (e.g. application/pdf)
fileSize long Yes File size in bytes (must be positive)
displayOrder integer No Sort order for multiple files

Request JSON Sample:

{
  "fileName": "design-kit-v2.fig",
  "contentType": "application/octet-stream",
  "fileSize": 52428800,
  "displayOrder": 1
}

Response JSON Sample:

{
  "success": true,
  "message": "Upload URL generated — upload directly to this URL then call /confirm",
  "data": {
    "uploadUrl": "https://s3.example.com/bucket/key?X-Amz-Signature=...",
    "objectKey": "digital-files/product-456/design-kit-v2.fig",
    "expiresAt": "2026-05-19T11:00:00"
  }
}

Upload Flow:

  1. Call POST /presign-upload → receive uploadUrl and objectKey
  2. PUT {uploadUrl} with binary file body (do not call the API for this step)
  3. Call POST /confirm with objectKey to register the file

16b. Confirm Upload

Purpose: Registers a file after direct upload to object storage. Must be called after the actual file upload succeeds.

Endpoint: POST api/v1/e-commerce/shops/{shopId}/products/{productId}/digital-files/confirm

Request Body:

Parameter Type Required Description
objectKey string Yes Returned by presign-upload
fileName string Yes Original file name
contentType string Yes MIME type
fileSize long Yes File size in bytes
displayOrder integer No Sort order

Response JSON Sample:

{
  "success": true,
  "message": "File confirmed and linked to product",
  "data": {
    "fileId": "aaa1bbbb-e89b-12d3-a456-426614174001",
    "productId": "456e7890-e89b-12d3-a456-426614174001",
    "fileName": "design-kit-v2.fig",
    "contentType": "application/octet-stream",
    "fileSize": 52428800,
    "fileVersion": 1,
    "displayOrder": 1,
    "isActive": true,
    "uploadedAt": "2026-05-19T10:45:00"
  }
}

16c. Get Product Files

Endpoint: GET api/v1/e-commerce/shops/{shopId}/products/{productId}/digital-files

Returns a list of DigitalFileResponse objects for all files linked to the product.


16d. Delete File

Endpoint: DELETE api/v1/e-commerce/shops/{shopId}/products/{productId}/digital-files/{fileId}

Additional Path Parameter:

Parameter Type Description
fileId UUID ID of the file to delete

16e. Toggle File Active Status

Endpoint: PATCH api/v1/e-commerce/shops/{shopId}/products/{productId}/digital-files/{fileId}/toggle

Query Parameters:

Parameter Type Required Description
isActive boolean Yes true to activate, false to deactivate

Deactivated files are hidden from buyers but not deleted.


17. Product Preview Management

Purpose: Manages a single preview file per product — a publicly accessible teaser shown to buyers before purchase. Distinct from private digital content files. Supports VIDEO, PDF, 3D models, and IMAGE previews.

Base URL: api/v1/e-commerce/shops/{shopId}/products/{productId}/preview

Access Level: 🔒 Protected (Requires shop owner or system admin role)

Authentication: Bearer Token

Path Parameters (shared):

ParameterTypeRequiredDescription
shopIdUUIDYesID of the shop
productIdUUIDYesID of the product (any type — PHYSICAL or DIGITAL)

Storage: Uploaded to nextgate-preview-content bucket (public read). The confirmed URL is permanent and requires no authentication to access.


17a. Presign Preview Upload

Purpose: Generates a presigned PUT URL. The client uploads the preview file directly to this URL, then calls /confirm.

Endpoint: POST api/v1/e-commerce/shops/{shopId}/products/{productId}/preview/presign-upload

Request Body:

ParameterTypeRequiredDescription
fileNamestringYesOriginal file name (used to build the storage key)
contentTypestringYesMIME type (e.g. video/mp4, application/pdf, image/jpeg, model/gltf-binary)
fileSizelongYesFile size in bytes (must be positive)

Request JSON Sample:

{
  "fileName": "product-trailer.mp4",
  "contentType": "video/mp4",
  "fileSize": 52428800
}

Response JSON Sample:

{
  "success": true,
  "message": "Preview upload URL generated — upload directly then call /confirm",
  "data": {
    "uploadUrl": "https://minio.example.com/nextgate-preview-content/preview/shop-id/product-id/uuid_product-trailer.mp4?X-Amz-Signature=...",
    "objectKey": "preview/shop-id/product-id/uuid_product-trailer.mp4",
    "expiresAt": "2026-05-19T11:30:00"
  }
}

Upload Flow:

  1. Call POST /presign-upload → receive uploadUrl and objectKey
  2. PUT {uploadUrl} with binary file body (client-to-MinIO directly, not through the API)
  3. Call POST /confirm with objectKey and previewType to link the file to the product

Error Responses:

  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

17b. Confirm Preview Upload

Endpoint: POST api/v1/e-commerce/shops/{shopId}/products/{productId}/preview/confirm

Request Body:

ParameterTypeRequiredDescription
objectKeystringYesReturned by presign-upload
previewTypePreviewTypeYesVIDEO, PDF, THREE_D, or IMAGE
previewDownloadablebooleanNoWhether viewers can download the file. Default: false (view/stream only)

Request JSON Sample:

{
  "objectKey": "preview/shop-id/product-id/uuid_product-trailer.mp4",
  "previewType": "VIDEO",
  "previewDownloadable": false
}

Response JSON Sample:

{
  "success": true,
  "message": "Preview confirmed and linked to product",
  "data": null
}

After confirm, the product's public response will include:

{
  "previewType": "VIDEO",
  "previewUrl": "https://minio.example.com/nextgate-preview-content/preview/shop-id/product-id/uuid_product-trailer.mp4",
  "previewDownloadable": false
}

Error Responses:

  • 400: Missing objectKey or previewType
  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

17c. Remove Preview

Purpose: Deletes the product's preview file from storage and clears previewType and previewUrl on the product.

Endpoint: DELETE api/v1/e-commerce/shops/{shopId}/products/{productId}/preview

Response JSON Sample:

{
  "success": true,
  "message": "Preview removed from product",
  "data": null
}

Error Responses:

  • 401: Authentication required
  • 403: Insufficient permissions
  • 404: Shop or product not found

Quick Reference

Common HTTP Status Codes

Code Meaning
200 OK Successful GET/PUT/PATCH
201 Created Successful POST (resource created)
400 Bad Request Invalid data, validation errors, business rule violations
401 Unauthorized Authentication required or invalid token
403 Forbidden Insufficient permissions
404 Not Found Resource not found or not accessible
409 Conflict Duplicate product name or business constraint violation
422 Unprocessable Entity Field-level validation errors
500 Internal Server Error Server error

User Access Levels

User Type Product Management Status Access
Public View active products only ACTIVE only
Authenticated View active products only ACTIVE only
Shop Owner Full CRUD on own shop All statuses
System Admin Full CRUD on all shops All statuses

Product Type Fulfillment Flows

Type Flow
PHYSICAL Payment → PENDING_SHIPMENT → Seller ships → Buyer confirms with 6-digit code → Escrow releases → COMPLETED
DIGITAL Payment → COMPLETED immediately → Escrow released → DigitalDownloadAccess records created → Buyer downloads

Product Status Lifecycle

DRAFT → ACTIVE → INACTIVE → ARCHIVED
  ↑                            ↓
  └───────── RESTORE ──────────┘

OUT_OF_STOCK ←→ ACTIVE (automatic based on inventory)
Status Public Visibility Available Actions
DRAFT Hidden Edit, Publish, Hard Delete
ACTIVE Visible Edit, Deactivate, Soft Delete
INACTIVE Hidden Edit, Activate, Soft Delete
OUT_OF_STOCK Visible (out of stock badge) Restock (auto-activates)
ARCHIVED Hidden Restore

Enums Reference

ProductType: PHYSICAL, DIGITAL

PreviewType: VIDEO, PDF, THREE_D, IMAGE — null means no preview

ProductCondition: NEW, USED_LIKE_NEW, USED_GOOD, USED_FAIR, REFURBISHED, FOR_PARTS

ReqAction: SAVE_DRAFT (→ DRAFT status), SAVE_PUBLISH (→ ACTIVE status)

UrgencyTag: NONE, NEW_ARRIVAL, LIMITED_EDITION, LIMITED_OFFER, FEW_REMAINS

PaymentFrequency: DAILY, WEEKLY, BI_WEEKLY, SEMI_MONTHLY, MONTHLY, QUARTERLY, CUSTOM_DAYS

FulfillmentTiming: IMMEDIATE (ship after down payment), AFTER_PAYMENT (layaway — ship after final payment)

SKU Format

SHP[8-CHAR-UUID]-[CATEGORY-3]-[BRAND-3]-[ATTRIBUTE-3]-[SEQUENCE-4]

Example: SHP12345678-ELE-APP-512-0001

Data Format Standards

  • Dates: ISO 8601 (2026-05-19T14:30:00Z)
  • Prices: Decimal with 2 decimal places, stored as BigDecimal
  • UUIDs: Standard UUID format
  • Pagination: 1-indexed page parameter
  • Colors: Hex format #RRGGBB
  • Percentages: Decimal format (20.00 = 20%)

Error Response Format

{
  "success": false,
  "message": "Human-readable error message",
  "error": {
    "code": "ERROR_CODE",
    "details": "Detailed information",
    "field": "fieldName (if field-specific)",
    "timestamp": "2026-05-19T14:30:00Z"
  }
}

Product Creation Flow

1. POST /shops/{shopId}/products?action=SAVE_DRAFT
   — create the product shell

2. POST /products/{shopId}/{productId}/installment-plans
   — add installment plans (if installmentEnabled)

3. POST /shops/{shopId}/products/{productId}/digital-files/presign-upload
   PUT {uploadUrl} (direct to storage)
   POST /shops/{shopId}/products/{productId}/digital-files/confirm
   — upload private digital files (DIGITAL products only)

4. POST /shops/{shopId}/products/{productId}/preview/presign-upload
   PUT {uploadUrl} (direct to storage)
   POST /shops/{shopId}/products/{productId}/preview/confirm
   — upload preview teaser (any product type, optional)
   — preview is stored in public bucket; URL is immediately accessible

5. PATCH /shops/{shopId}/products/{productId}/publish
   — publish when ready

Preview vs Digital Files

PreviewDigital Files
Who sees itEveryone (before purchase)Buyers only (after payment)
Bucketnextgate-preview-content (public)nextgate-digital-content (private)
AccessPermanent public URLPresigned URL, expires per downloadExpiryDays
CountOne per productMultiple files per product
ProductsPHYSICAL or DIGITALDIGITAL only
PurposeTeaser/sample before buyingActual purchased content