> Documentation index: [Saleor](/llms.txt) · [This section](/developer/llms.txt)
> Source: https://docs.saleor.io/developer/models

# Models

API Compatibility Notice

While we've updated the terminology in the documentation to use "Models" and "Model Types", the API endpoints and GraphQL schema still use `pages` and `pageTypes`. This is temporary, and we plan to update the API to match the new terminology soon.

<a id="overview"></a>

## Overview

Models provide a flexible mechanism for managing both traditional content and structured data entities that extend your commerce domain beyond the standard Product/Category/Collection model. Think of them as structured documents within Saleor.

<a id="core-concepts"></a>

## Core Concepts

<a id="model-types"></a>

### Model Types

A Model Type defines the schema for a group of models. It determines what attributes a model will have and how the model can be used. Think of Model Types as templates or schemas. For instance, a "Blog Post" model type might have attributes like `Author`, `PublishedDate`, and `Tags`.

You must create a Model Type before you can create any Model.

info

You can manage Model Types in the Dashboard's -> Modeling -> _Model Types_ view.

<a id="attributes"></a>

### Attributes

Attributes define typed fields that can be reused across products and models. When creating an attribute, it must be explicitly [assigned to either `PRODUCT` or `PAGE` type](/api-reference/attributes/enums/attribute-type-enum.md).

<a id="models-1"></a>

### Models

A Model is an instance of a Model Type, enriched with specific attribute values and optionally a rich content block. Models can be created, linked to other entities, published, or removed.

info

You can manage Models in the Dashboard's -> Modeling -> _Models_ view.

<a id="example-use-case"></a>

## Example Use Case

**Modeling Scent Profiles in Perfume Store**

Consider a specialized perfume store, where each product is a fragrance. Fragrances are complex blends, often composed of multiple scent profiles like "Citrus", "Woody", or "Floral". These profiles are shared across products.

Here's a breakdown of the entities and relationships:

```mermaid
graph TD
  ProductTypeFragrance["Product Type: Fragrance"]
  ProductFragrance["Product: Sunlit Grove"]
  AttributeScentProfiles["Product Attribute: Scent Profiles (REFERENCE)"]
  ModelTypeScentProfile["Model Type: Scent Profile"]
  ModelCitrus["Model: Citrus Zest"]
  ModelGreen["Model: Green Woods"]
  AttrFamily["Attribute: Scent Family (Dropdown)"]
  AttrNotes["Attribute: Notes Description (Rich Text)"]

  ProductTypeFragrance --> ProductFragrance
  ProductFragrance --> AttributeScentProfiles
  AttributeScentProfiles --> ModelCitrus
  AttributeScentProfiles --> ModelGreen

  ModelCitrus --> AttrFamily
  ModelCitrus --> AttrNotes
  ModelGreen --> AttrFamily
  ModelGreen --> AttrNotes

  ModelTypeScentProfile --> ModelCitrus
  ModelTypeScentProfile --> ModelGreen
```

-   **Product Type:** `Fragrance`
-   **Product Attribute:** `Scent Profiles`
    -   Type: `REFERENCE`
    -   Entity: `Page`
-   **Model Type:** `Scent Profile`
-   **Model Attributes:**
    -   `Scent Family` – Dropdown field (e.g., _Citrus_, _Woody_, _Floral_)
    -   `Notes Description` – Rich text field (e.g., _Bright and zesty with a hint of green bitterness_)

For the fragrance **Sunlit Grove**, the following scent profiles might be selected:

-   `Citrus Zest`
-   `Green Woods`

Each of these is a **Model** of type `Scent Profile`, reused across multiple products and enriched with structured attributes.

In the storefront UI, this structure enables rich product pages that showcase the fragrance's composition. For example, the Sunlit Grove product page might display its scent profiles in a dedicated section, with each profile (Citrus Zest, Green Woods) showing its family type and detailed notes description.

<a id="lifecycle"></a>

## Lifecycle

<a id="creating-a-model"></a>

### Creating a Model

To [create a model](/api-reference/pages/mutations/page-create.md) through API, you must first define the [model type](/api-reference/pages/mutations/page-type-create.md) and any required attributes.

info

Creating a model requires the [`MANAGE_PAGES` permission](/developer/permissions.md#available-permissions).

**Mutation**

```graphql
mutation PageCreate($input: PageCreateInput!) {
  pageCreate(input: $input) {
    page {
      id
      title
    }
    errors {
      field
      message
    }
  }
}
```

**Variables**

```json
{
  "input": {
    "title": "Citrus Zest",
    "slug": "citrus-zest",
    "isPublished": true,
    "pageType": "UGFnZVR5cGU6NDY="
  }
}
```

<a id="getting-models"></a>

### Getting Models

You can get individual model details using the [`page`](/api-reference/pages/queries/page.md) query:

**Query**

```graphql
query GetPage($id: ID!) {
  page(id: $id) {
    id
    title
    content
    attributes {
      attribute {
        name
        slug
      }
      values {
        name
      }
    }
  }
}
```

**Variables**

```json
{
  "id": "UGFnZToz"
}
```

or you can get multiple models using the [`pages`](/api-reference/pages/queries/pages.md) query:

**Query**

```graphql
query GetPages($first: Int, $filter: PageFilterInput) {
  pages(first: $first, filter: $filter) {
    totalCount
    edges {
      node {
        id
        title
        attributes {
          attribute {
            name
            slug
          }
          values {
            name
          }
        }
      }
    }
  }
}
```

**Variables**

```json
{
  "first": 5,
  "filter": {
    "ids": ["UGFnZToz", "UGFnZTo0"]
  }
}
```

<a id="linking-models"></a>

### Linking Models

Models can reference or be referenced by other entities through attribute of type [REFERENCE](/api-reference/attributes/enums/attribute-input-type-enum.md#reference). The selection of referenceable entities is determined by [`AttributeEntityTypeEnum`](/api-reference/attributes/enums/attribute-entity-type-enum.md) and currently includes `PAGE`, `PRODUCT` and `PRODUCT_VARIANT`.

**Mutation**

```graphql
mutation ProductUpdate($id: ID, $input: ProductInput!) {
  productUpdate(id: $id, input: $input) {
    product {
      id
      name
    }
    errors {
      field
      message
    }
  }
}
```

**Variables**

```json
{
  "id": "UHJvZHVjdElE",
  "input": {
    "attributes": [
      {
        "id": "QXR0cmlidXRlSWQ=",   # Product Attribute of type REFERENCE for scent profiles
        "references": [
          "UGFnZUlE"   # ID of the Citrus Zest model
        ]
      }
    ]
  }
}

```

You can also model relationships between Models using a reference attribute or by embedding slugs/IDs in the model metadata.

<a id="querying-linked-entities"></a>

#### Querying Linked Entities

Below is an example of how to query the linked entities using the [`product`](/api-reference/products/queries/product.md) query:

```graphql
query GetProductWithScentProfiles($productId: ID!) {
  product(id: $productId) {
    id
    name
    attributes {
      attribute {
        id
        slug # We are looking for "scent-profiles"
      }
      values {
        reference # This gives the Model ID
      }
    }
  }
}
```

The response will contain the ids of the linked models. You can then use the [`page` query](#getting-models) to get the details of the linked models.

<a id="publishing-models"></a>

### Publishing Models

Models can be visible or hidden. You can control their visibility using:

-   `isPublished` (Boolean): Sets current visibility.
-   `publicationDate` (Date): Can schedule a future publication. The model won't appear on the storefront until this date.

info

If `isPublished` is false, only users with the [`MANAGE_PAGES`](/developer/permissions.md#available-permissions) permission will be able to successfully retrieve it.

You can update the value of those fields using [`pageUpdate`](/api-reference/pages/mutations/page-update.md) mutation:

**Mutation**

```graphql
mutation PageUpdate($id: ID!, $input: PageInput!) {
  pageUpdate(id: $id, input: $input) {
    page {
      id
      title
      isPublished
    }
    errors {
      field
      message
    }
  }
}
```

**Variables**

```json
{
  "id": "UGFnZUlE",
  "input": {
    "isPublished": true,
    "publicationDate": "2025-04-15"
  }
}
```

<a id="deleting-models"></a>

### Deleting Models

Use [`pageDelete`](/api-reference/pages/mutations/page-delete.md) for single models or [`pageBulkDelete`](/api-reference/pages/mutations/page-bulk-delete.md) for multiple. Deleting a Model is permanent. Deleting a Model Type might be restricted if Models are using it.

```graphql
mutation DeletePage($id: ID!) {
  pageDelete(id: $id) {
    page {
      id
    }
    errors {
      field
      code
      message
    }
  }
}
```

```graphql
mutation DeleteMultiplePages($ids: [ID!]!) {
  pageBulkDelete(ids: $ids) {
    count
    errors {
      field
      code
      message
    }
  }
}
```

<a id="webhooks"></a>

## Webhooks

Here are the webhooks that are available for models:

-   [`PAGE_TYPE_CREATED`](/api-reference/pages/objects/page-type-created.md)
-   [`PAGE_TYPE_UPDATED`](/api-reference/pages/objects/page-type-updated.md)
-   [`PAGE_TYPE_DELETED`](/api-reference/pages/objects/page-type-deleted.md)
-   [`PAGE_CREATED`](/api-reference/pages/objects/page-created.md)
-   [`PAGE_UPDATED`](/api-reference/pages/objects/page-updated.md)
-   [`PAGE_DELETED`](/api-reference/pages/objects/page-deleted.md)
