Skip to content

Product Submissions

Table of Contents

Overview

The Product Submissions feature lets customers propose new products for the catalog through the customer portal. Submissions are queued for staff review: approved submissions become first-class Product records, while rejected submissions return to the customer with a reason.

This gives customers a self-service path to expand the catalog without giving them direct write access, and gives staff an approval gate to enforce SKU, dimensional, and handling-class standards before a product enters the system.

Key Capabilities:

  • Customer-initiated submission form with inline SKU-availability checking
  • Three-state lifecycle: Pending, Approved, Rejected
  • Approve action atomically creates the catalog Product and relinks any pending delivery-request lines
  • Reject action captures a required reason that is shown back to the customer
  • In-app notifications on create / approve / reject for both audiences
  • Full audit trail via the platform audit module

Who can submit?

Only portal users linked to a customer account and holding the products:submit permission may create submissions. Internal staff without a customer link cannot submit — they review.

Who can approve or reject?

Only users with the products:manage permission see the Approve and Reject buttons. Viewing the queue requires products:view.

Workflow at a Glance

graph LR
    A[Customer fills<br/>Submit Product form] --> B[SKU availability<br/>check]
    B --> C[Submission<br/>PENDING]
    C --> D{Staff<br/>review}
    D -->|Approve| E[Catalog Product<br/>created]
    D -->|Reject| F[Rejection reason<br/>captured]
    E --> G[Customer notified<br/>APPROVED]
    F --> H[Customer notified<br/>REJECTED]

    style A fill:#e3f2fd
    style C fill:#fff3e0
    style D fill:#fff3e0
    style E fill:#e8f5e9
    style F fill:#ffebee
    style G fill:#e8f5e9
    style H fill:#ffebee

Customer Workflow

This section is for customer-portal users submitting products for catalog inclusion.

Accessing the Submission Form

  1. Sign in to the Customer Portal
  2. Open the Products page from the sidebar
  3. Click Submit Product in the top-right corner
  4. The Submit Product modal opens

Delivery request shortcut

If you are filling out a delivery request and the product you need is not in the catalog, the Create Delivery Request flow includes a shortcut that opens this same submission form and automatically links the new submission to the in-progress delivery request. Once the submission is approved, the delivery-request line is re-pointed to the real product with no further action needed from you.

Required and Optional Fields

Field Required Notes
Product Name Yes Up to 255 characters. Example: Heavy Duty Widget
SKU Yes Up to 100 characters. Letters, numbers, and hyphens only. Checked live for availability.
Unit of Measure Yes One of: EACH, CASE, PALLET, LB, KG, OZ, G
Description No Up to 2,000 characters. Free-form product description.
Weight No In pounds. Decimal allowed.
Length / Width / Height No In inches. Decimal allowed.
Cases per Pallet No Whole number, 1 – 9,999.
Notes No Up to 2,000 characters. Special handling, compliance, or any info for the reviewer.

Provide dimensions and weight when possible

Reviewers use weight and dimensional data to assign storage and freight classes during approval. Submissions missing this data are approvable but may be sent back for revision if your operations team needs it upfront.

SKU Availability

As you type the SKU, the form debounces and calls the availability endpoint. You will see one of three states:

  • Available — green check, safe to proceed
  • Already in the catalog — the SKU belongs to an existing approved product
  • Pending approval — another submission (possibly your own) is already using this SKU

If the SKU is taken you must change it before you can submit.

Submitting

  1. Review all fields
  2. Click Submit for Review
  3. A success toast confirms the submission; the modal closes

The submission is created in PENDING status. Both staff reviewers and your own customer account receive an in-app notification.

Checking Submission Status

  1. Navigate to Products in the portal
  2. Open the My Submissions tab (or click the notification link)
  3. The table shows every submission you have made, scoped automatically to your customer account

The Status column badge is color-coded:

Badge Meaning
Pending Waiting for staff review
Approved Accepted — a catalog product has been created
Rejected Declined — open the row to see the rejection reason

Clicking a row opens the detail panel, which includes the fields you submitted, the review outcome, the reviewer's name, and the review timestamp. Rejected rows display the full Rejection Reason so you can correct and resubmit.


Staff (Admin) Workflow

This section is for internal staff with the products:manage permission reviewing the submission queue.

Reviewing the Submission Queue

Navigate to Product Submissions from the main sidebar. The page lives at /product-submissions and defaults to the Pending filter so you see the active queue first.

Interface elements:

  • Search bar — search by product name or SKU
  • Status filterAll Statuses, Pending, Approved, Rejected (default: Pending)
  • Submissions table — one row per submission
  • Pagination — 20 rows per page by default
  • Row click — opens the Review modal

Table columns:

Column Description
Product Name Submitted product name
SKU Proposed SKU
Customer Submitting customer's company name
Submitted By Portal user who submitted
Status Color-coded status badge
Submitted Relative timestamp (e.g., "2 hours ago")

Opening a Submission for Review

Click any row to open the Review modal. The modal shows every field the customer entered:

  • Identification: name, SKU, status badge
  • Logistics data: unit of measure, weight, length × width × height, cases per pallet
  • Description and Notes (if provided)
  • Submission metadata: customer, submitted-by user, submission timestamp
  • For reviewed submissions: Reviewed By, Reviewed At, and Rejection Reason (rejected only) or Linked Product (approved only)

Approving a Submission

Approving a submission creates a real Product in the catalog and links back to the submission.

  1. Open the submission in the Review modal
  2. (Optional) Expand Show Overrides to adjust any of the following before creating the product:

    Override Purpose
    SKU Normalize the SKU to your internal scheme
    Name Tidy up the display name
    Storage Class Assign a storage class (e.g., AMBIENT, REFRIGERATED)
    Freight Class Assign a freight class for rating
    NMFC Code National Motor Freight Classification code
    Lot Tracked Enable lot tracking on the new product
    Serial Tracked Enable serial-number tracking
    Reorder Point / Reorder Quantity / Max Stock Inventory planning defaults
    Cost / Price Financial defaults
  3. Click Approve

What the system does on approve (wrapped in a single transaction):

  1. Creates a new Product entity using the submission's fields plus any overrides
  2. Sets the submission status to APPROVED, stamps reviewedAt and reviewedByUserId, and stores the new productId
  3. Re-points any pending DeliveryRequestLine rows that referenced this submission so they now reference the real product
  4. Emits product-submission.approved, which sends the customer an in-app notification
  5. Writes a STATUS_CHANGE entry to the audit log

SKU conflicts at approval time

If another product takes the same SKU between submission and approval (a TOCTOU race), the approve action fails with a conflict error. Use the SKU override field to assign a different SKU and try again.

Rejecting a Submission

  1. Open the submission in the Review modal
  2. Scroll to the Reject section
  3. Enter a Rejection Reason (required — the API rejects empty reasons with a 400)
  4. Click Reject

What the system does on reject:

  1. Sets the submission status to REJECTED, stamps reviewedAt and reviewedByUserId, and stores the rejectionReason
  2. Collects any delivery-request lines that referenced this submission so the customer knows which requests are blocked
  3. Emits product-submission.rejected, which sends the customer an in-app notification containing the rejection reason
  4. Writes a STATUS_CHANGE entry to the audit log

Write useful rejection reasons

The rejection reason is shown verbatim to the customer. Be specific and actionable — for example, "Weight and pallet dimensions required for LTL rating — please resubmit with weight and L/W/H" is far more useful than "Missing info". The customer can resubmit with the same SKU once the original submission is rejected.

Reason-Code Guidance

There are no hard-coded reason codes — the field is free-form. Common patterns most operations teams use:

Pattern Example reason text
Missing data "Dimensions required for pallet calculation — please add L/W/H and cases per pallet."
Duplicate "Equivalent product already exists in the catalog as SKU WIDGET-001. Please use that SKU on your delivery request."
Non-compliant SKU "SKU does not follow XXX-000 format required for this customer. Please resubmit as HDW-100."
Needs classification review "Hazmat classification required before onboarding. Please email compliance@… with the SDS and resubmit."
Out of scope "This product falls outside the categories in your current MSA. Contact your account manager."

Once Reviewed, a Submission Is Locked

Both Approve and Reject require the submission to be in PENDING status. Attempting either on an already-reviewed submission returns a 400 error. If a mistake is made:

  • For an erroneous rejection — the customer resubmits. You cannot "un-reject" from the UI.
  • For an erroneous approval — deactivate the resulting catalog product through the normal Products admin flow. The submission record itself remains approved for audit integrity.

API Reference

All endpoints are prefixed with the platform API base URL and require a Bearer token.

Method Path Permission Purpose
POST /product-submissions products:submit Customer creates a submission
GET /product-submissions products:view List submissions (auto-scoped to customer for portal users)
GET /product-submissions/check-sku/:sku products:submit Live SKU-availability check
GET /product-submissions/:id products:view Submission details with reviewer and product relations
PATCH /product-submissions/:id/approve products:manage Approve and create catalog product
PATCH /product-submissions/:id/reject products:manage Reject with a required rejectionReason

List filters supported on GET /product-submissions:

  • status[eq]PENDING, APPROVED, or REJECTED
  • status[in] — comma-separated list
  • customerId[eq] — staff-only scoping (portal users are always scoped to their own customer)
  • search — matches name or SKU
  • page, pageSize, sortBy, sortOrder — standard pagination and sort (sortBy: createdAt, name, sku, status)

Response shapes follow the standard { data, meta } envelope used elsewhere in the API. Error responses use standard HTTP status codes: 400 for validation, 404 for not-found, 409 for SKU conflict.


Notifications

The event listener creates in-app notifications on three lifecycle events:

Event Recipients Content
product-submission.created Staff with products:manage for the submission's warehouse "New product submission — Name (SKU) from Customer"
product-submission.approved The submitting portal user (and their customer organization) "Your product submission Name (SKU) was approved"
product-submission.rejected The submitting portal user (and their customer organization) "Your product submission Name (SKU) was rejected — reason"

Clicking a notification deep-links to the submission detail. In the staff UI this opens the Review modal; in the customer portal it opens the status view with the submission highlighted.


Audit Trail

Every state change is recorded through the platform audit module with entityType = product-submission:

Action When Captured Fields
CREATE Submission is created name, sku, status
STATUS_CHANGE Approval status (PENDING → APPROVED), productId (null → new product ID)
STATUS_CHANGE Rejection status (PENDING → REJECTED), rejectionReason

The audit entries include the acting user ID and timestamp. For investigation and compliance queries, see the audit-log documentation.

Audit log doc — in progress

A dedicated audit-log reference is tracked under a separate ticket (issue #13). Once published it will live at administration/audit-log.md. TODO: convert to a proper link once #13 ships.


Troubleshooting

"User must be linked to a customer account to submit products"

Cause: The signed-in user has no customerId set on their profile.

Solution: A system administrator must edit the user in Users and set a default customer linkage, or the user must sign in with a portal account that belongs to a customer.


"No warehouse assigned. Please contact your warehouse representative."

Cause: The submitting user has neither a preferred default warehouse nor a warehouse data filter.

Solution: Set a default warehouse on the user's profile preferences, or add a warehouse data filter assignment.


"SKU already exists in the product catalog"

Cause: An active approved product already uses this SKU.

Solution: Use the existing catalog SKU on your delivery request — no submission is needed. If the existing product truly is different, pick a unique SKU.


"SKU is already pending approval"

Cause: Another submission (possibly your own, from earlier) is sitting in the PENDING queue with this SKU.

Solution: Check My Submissions — you may already have an open submission. Wait for that one to be reviewed, or pick a different SKU.


Approve button fails with "SKU was just taken"

Cause: Between opening the review modal and clicking Approve, another product grabbed the same SKU.

Solution: Expand Show Overrides, enter a different SKU in the SKU override field, and click Approve again.


"Cannot approve/reject a submission in APPROVED status"

Cause: The submission has already been reviewed. Approve and Reject only work on PENDING submissions.

Solution: See Once Reviewed, a Submission Is Locked.


  • Order Processing — how approved products flow into orders and delivery requests
  • Customers — managing the customer accounts that portal submitters belong to
  • Users — managing the products:submit, products:view, and products:manage permissions
  • Bulk Upload — alternate path for importing large product catalogs (staff-only)
  • Audit Log — in progress, tracked in issue #13

Support

For product-submission assistance: