Skip to main content
Categories form the top level of the business hierarchy. Each category can contain sub-categories, which in turn group offers. Categories also define custom fields (including computed fields with formulas) that are inherited by all offers within the category.
See the Business Hierarchy feature page for UI guidance and conceptual overview.

Base path

/api/v1/categories        # Categories
/api/v1/sub-categories    # Sub-categories

Categories

List categories

GET /api/v1/categories
Returns a paginated list of categories for the current tenant, ordered by ordinal ascending. Each category includes its sub-categories with offer counts.

Query parameters

ParameterRequiredTypeDescription
limitNointegerMaximum results per page. Default 25.
cursorNostringCursor for keyset pagination.

Response 200

{
  "data": [
    {
      "id": "cat_01",
      "tenantId": "t_001",
      "name": "Acquisition",
      "description": "New customer acquisition offers.",
      "icon": "user-plus",
      "color": "blue",
      "status": "active",
      "ordinal": 0,
      "customFields": [
        {
          "key": "base_rate",
          "label": "Base Rate",
          "type": "number",
          "defaultValue": 0
        },
        {
          "key": "personalized_rate",
          "label": "Personalized Rate",
          "type": "computed",
          "formula": "base_rate * (1 + customer.loyalty_score / 100)",
          "outputType": "number"
        }
      ],
      "subCategories": [
        {
          "id": "sub_01",
          "name": "Credit Cards",
          "_count": { "offers": 12 }
        }
      ],
      "createdAt": "2026-03-10T12:00:00.000Z",
      "updatedAt": "2026-03-12T09:30:00.000Z"
    }
  ],
  "pagination": {
    "total": 4,
    "limit": 25,
    "hasMore": false,
    "nextCursor": null
  }
}

Create a category

POST /api/v1/categories

Request body

FieldRequiredTypeDescription
nameYesstring (1-255)Unique category name.
descriptionNostringCategory description.
iconNostringIcon identifier (e.g., Lucide icon name).
colorNostringDisplay color. Default "blue".
statusNoenumdraft, active (default), paused, archived.
ordinalNointeger (>= 0)Sort order. Default 0.
customFieldsNoarrayCustom field definitions (see below). Max 500 items.

Custom field object

FieldRequiredTypeDescription
keyYesstringMachine-readable field key.
labelYesstringHuman-readable label.
typeYesstringField type: text, number, boolean, select, computed.
defaultValueNoanyDefault value for the field.
formulaConditionalstringFormula expression. Required when type is computed.
outputTypeConditionalenumnumber or text. Required when type is computed.
Computed fields require both a valid formula and an outputType (number or text). The formula is validated using the formula engine. Supported namespaces: fieldName (sibling fields), customer.* (enriched data), attributes.* (request-time attributes).

Example request

{
  "name": "Retention",
  "description": "Offers aimed at retaining existing customers.",
  "color": "green",
  "ordinal": 1,
  "customFields": [
    { "key": "discount_pct", "label": "Discount %", "type": "number", "defaultValue": 10 },
    {
      "key": "final_discount",
      "label": "Final Discount",
      "type": "computed",
      "formula": "discount_pct * (customer.tenure_years > 5 ? 1.2 : 1.0)",
      "outputType": "number"
    }
  ]
}

Response 201

Returns the created category with sub-categories relation.

Error codes

CodeReason
400Validation error (missing name, invalid computed field).
409A category with that name already exists.
415Content-Type is not application/json.

Update a category

PUT /api/v1/categories
Updates an existing category. Only provided fields are changed.

Request body

FieldRequiredTypeDescription
idYesstringCategory ID to update.
All other fields from the create schema are accepted as optional.

Response 200

Returns the updated category object.

Delete a category

DELETE /api/v1/categories?id={categoryId}
Deletes a category by ID. The API returns 409 if offers or sub-categories still reference the category.

Query parameters

ParameterRequiredTypeDescription
idYesstringCategory ID to delete.

Response 204

Empty body on success.

Error codes

CodeReason
400Missing id query parameter.
409Category still has offers or sub-categories. Reassign them first.

Sub-categories

Sub-categories live under a category and group related offers.

List sub-categories

GET /api/v1/sub-categories

Query parameters

ParameterRequiredTypeDescription
categoryIdNostringFilter to a specific parent category.
limitNointegerMaximum results per page. Default 25.
cursorNostringCursor for keyset pagination.

Response 200

{
  "data": [
    {
      "id": "sub_01",
      "tenantId": "t_001",
      "categoryId": "cat_01",
      "name": "Credit Cards",
      "description": "",
      "icon": "",
      "status": "active",
      "ordinal": 0,
      "customFields": [],
      "category": { "id": "cat_01", "name": "Acquisition" },
      "_count": { "offers": 12 }
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 25,
    "hasMore": false,
    "nextCursor": null
  }
}

Create a sub-category

POST /api/v1/sub-categories

Request body

FieldRequiredTypeDescription
categoryIdYesstringParent category ID.
nameYesstringSub-category name.
descriptionNostringDescription.
iconNostringIcon identifier.
statusNoenumdraft, active (default), paused, archived.
ordinalNointeger (>= 0)Sort order. Default 0.
customFieldsNoarrayCustom field definitions (same schema as categories).

Response 201

Returns the created sub-category with its parent category relation.

Update a sub-category

PUT /api/v1/sub-categories

Request body

FieldRequiredTypeDescription
idYesstringSub-category ID to update.
All other fields are optional.

Response 200

Returns the updated sub-category object.

Delete a sub-category

DELETE /api/v1/sub-categories?id={subCategoryId}

Query parameters

ParameterRequiredTypeDescription
idYesstringSub-category ID to delete.

Response 204

Empty body on success.

Role requirements

MethodMinimum role
GETviewer
POSTeditor
PUTeditor
DELETEeditor

Business Hierarchy

Learn more about organising categories and sub-categories in the platform UI.