Supercommerce API Docs
Admin API

Product Attribute Module — Admin

HTTP surface for managing the platform-wide catalogue of product attributes (typed metadata fields — Material, Capacity, Heel Height, etc.) and attribute groups that bundle…

HTTP surface for managing the platform-wide catalogue of product attributes (typed metadata fields — Material, Capacity, Heel Height, etc.) and attribute groups that bundle attributes together for application to specific product families.

Source: api-modules/product-attribute/src/controllers/admin-product-attribute.controller.ts, api-modules/product-attribute/src/controllers/admin-product-attribute-group.controller.ts.

Attributes are catalog-wide definitions. Vendors apply them (or a group of them) to their products via the vendor-side endpoints. The admin surface owns the universe of attributes / groups; vendors only consume.


Conventions

Authentication

All endpoints require a Better-Auth admin session and a role granting the matching productAttribute:* permission.

Endpoint groupPermission
GET /admin/product-attributes, GET /admin/product-attributes/:id, GET /admin/product-attribute-groups, GET /admin/product-attribute-groups/:idproductAttribute: read
POST /admin/product-attributes, POST /admin/product-attribute-groupsproductAttribute: create
PUT /admin/product-attributes/:id, POST /admin/product-attributes/:id/restore, PUT /admin/product-attribute-groups/:id, POST /admin/product-attribute-groups/:id/restoreproductAttribute: update
DELETE /admin/product-attributes/:id, DELETE /admin/product-attribute-groups/:idproductAttribute: delete

Response envelope

Successful responses are wrapped by ResponseInterceptor:

{
  "data": <payload>,
  "message": "Success",
  "statusCode": 200,
  "metadata": { /* optional, e.g. pagination */ }
}

Error envelope

statusCodeerrorCode examples
400BAD_REQUEST, VALIDATION_ERROR
401UNAUTHORIZED
403FORBIDDEN
404NOT_FOUND
409UNIQUE_VIOLATION (code already in use)
500INTERNAL_SERVER_ERROR, DATABASE_ERROR

Lifecycle

Attributes and groups soft-delete via deletedAt. DELETE flips it; POST /:id/restore clears it.


Domain types

ProductAttributeResponse

type ProductAttributeType = "multi_select" | "text" | "boolean" | "number" | "select";

type ProductAttributeValueResponse = {
  id: string;
  attributeId: string;
  value: string;                                 // 1..255
  sortOrder: number;
  createdAt: string;
  updatedAt: string;
  deletedAt: string | null;
};

type ProductAttributeResponse = {
  id: string;
  title: string;                                 // 1..255
  code: string;                                  // lowercase alnum + hyphens
  type: ProductAttributeType;
  isRequired: boolean;
  isUnique: boolean;
  createdAt: string;
  updatedAt: string;
  deletedAt: string | null;
  values: ProductAttributeValueResponse[];       // present for "select"/"multi_select"
};

ProductAttributeGroupResponse

type ProductAttributeGroupResponse = {
  id: string;
  title: string;
  code: string;
  createdAt: string;
  updatedAt: string;
  deletedAt: string | null;
  attributes: Array<ProductAttributeResponse & { sortOrder: number }>;
};

Product attributes

Base path: /admin/product-attributes.

GET /admin/product-attributes — List attributes

Required permission: productAttribute: read. Standard QueryDto (page / limit / search / filters[]).

Response 200 — paginated envelope of ProductAttributeResponse[].


GET /admin/product-attributes/:id — Get an attribute

Required permission: productAttribute: read.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown id

POST /admin/product-attributes — Create an attribute

Required permission: productAttribute: create.

Body

{
  "title": "Material",
  "code": "material",
  "type": "multi_select",
  "isRequired": false,
  "isUnique": false,
  "values": [
    { "value": "Cotton",  "sortOrder": 0 },
    { "value": "Linen",   "sortOrder": 1 },
    { "value": "Polyester", "sortOrder": 2 }
  ]
}
FieldTypeConstraints
titlestring1..255
codestring1..255, lowercase alnum + hyphens
typeenummulti_select / text / boolean / number / select
isRequiredbooleanDefault false
isUniquebooleanDefault false
valuesArray<{value, sortOrder}>?value: 1..255; sortOrder: >= 0. Relevant for select / multi_select

Response 201ProductAttributeResponse.

Errors

StatusCodeWhen
400VALIDATION_ERRORBody fails zod
409UNIQUE_VIOLATIONcode already taken

PUT /admin/product-attributes/:id — Update an attribute

Required permission: productAttribute: update. Partial — every field optional.

Response 200 — updated ProductAttributeResponse.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown id

DELETE /admin/product-attributes/:id — Soft-delete

Required permission: productAttribute: delete.

Response 200 — deleted ProductAttributeResponse.


POST /admin/product-attributes/:id/restore — Restore

Required permission: productAttribute: update.

Response 200 — restored ProductAttributeResponse.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown id

Product attribute groups

Base path: /admin/product-attribute-groups.

GET /admin/product-attribute-groups — List groups

Required permission: productAttribute: read. Standard QueryDto.

Response 200 — paginated envelope of ProductAttributeGroupResponse[].


GET /admin/product-attribute-groups/:id — Get a group

Required permission: productAttribute: read.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown id

POST /admin/product-attribute-groups — Create a group

Required permission: productAttribute: create.

Body

{
  "title": "Apparel essentials",
  "code": "apparel-essentials",
  "attributes": [
    { "attributeId": "01J9...", "sortOrder": 0 },
    { "attributeId": "01J9...", "sortOrder": 1 }
  ]
}
FieldTypeConstraints
titlestring1..255
codestring1..255, lowercase alnum + hyphens
attributesArray<{attributeId, sortOrder}>?attributeId required; sortOrder >= 0

Response 201ProductAttributeGroupResponse.

Errors

StatusCodeWhen
400VALIDATION_ERRORBody fails zod
409UNIQUE_VIOLATIONcode already taken

PUT /admin/product-attribute-groups/:id — Update a group

Required permission: productAttribute: update. Partial. When attributes is sent it replaces the entire member set (whole-set semantics, not deep-merge).

Response 200 — updated ProductAttributeGroupResponse.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown id

DELETE /admin/product-attribute-groups/:id — Soft-delete

Required permission: productAttribute: delete.

Response 200 — deleted ProductAttributeGroupResponse.


POST /admin/product-attribute-groups/:id/restore — Restore

Required permission: productAttribute: update.

Response 200 — restored ProductAttributeGroupResponse.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown id

  • admin-rbac — gates every endpoint via productAttribute:*. See admin-rbac.md.
  • catalog — vendor-side product create/update endpoints apply attributes (or an entire group) to a product.

On this page