Skip to content

Platform Elements

Platform Elements are dynamic, platform-specific components that consuming platforms register with EngageHQ and resolve client-side at render time.

Overview

Unlike built-in content sections that EngageHQ renders directly (hero, content block, gallery, etc.), Platform Elements represent UI components that belong to a specific consuming platform. EngageHQ stores the element reference and its configuration, but the actual rendering is handled entirely by the consuming application.

This enables platforms like ecom360, KitchenClick, or AdConnect to inject their own specialized components into EngageHQ-managed content without requiring changes to the EngageHQ content model.

How it works

  1. Registration -- A platform registers its available elements with EngageHQ via the API or the Retail Success Platform admin UI (e.g., "Popular Sale Items", "Weekly Ad Banner")
  2. Authoring -- Content editors can insert registered platform elements into pages and homepages through the content builder
  3. Storage -- EngageHQ stores the element reference (platform_key + element_key) along with any editor-configured values
  4. Delivery -- The public Content API returns platform element sections alongside built-in sections
  5. Resolution -- The consuming application matches each platform element to a local component and renders it client-side

Client-Side Resolution

Platform elements are never rendered server-side by EngageHQ. The consuming application is responsible for mapping each platform_key:element_key combination to a concrete component. See the JavaScript, Vue, and React examples for implementation patterns.

Admin UI

Platform elements can also be registered and managed through the Retail Success Platform admin dashboard under Content Studio > Platform Elements, without using the API directly.


Required Permissions

All Platform Element management endpoints require a valid JWT with the appropriate engagehq:platform_elements.* scope:

EndpointRequired Scope
GET list / active / showengagehq:platform_elements.view
POST registerengagehq:platform_elements.create
PUT updateengagehq:platform_elements.update
DELETE deleteengagehq:platform_elements.delete

Requests missing the required scope will receive a 403 Forbidden response.


Registration API

Register a new platform element so it becomes available in the content builder.

Required scope: engagehq:platform_elements.create

http
POST /api/v1/content/platform-elements

Request Body

json
{
  "platform_key": "ecom360",
  "element_key": "popular-sale-items",
  "display_name": "Popular Sale Items",
  "description": "Displays a carousel of current popular/sale items",
  "icon": "ShoppingBagIcon",
  "category": "commerce",
  "config_schema": {
    "type": "object",
    "properties": {
      "max_items": {
        "type": "integer",
        "default": 12,
        "minimum": 1,
        "maximum": 50
      },
      "layout": {
        "type": "string",
        "enum": ["carousel", "grid"],
        "default": "carousel"
      }
    }
  },
  "default_config": {
    "max_items": 12,
    "layout": "carousel"
  },
  "allowed_content_types": ["homepage", "landing"],
  "supported_settings": ["padding", "max_width"]
}

Request Fields

FieldTypeRequiredDescription
platform_keystringYesIdentifier for the consuming platform (e.g., ecom360, kitchenclick)
element_keystringYesUnique element identifier within the platform (e.g., popular-sale-items)
display_namestringYesHuman-readable name shown in the content builder
descriptionstringNoDescription shown to content editors
iconstringNoIcon identifier for the content builder UI
categorystringNoGrouping category (e.g., commerce, navigation, media)
config_schemaobjectNoJSON Schema defining editor-configurable properties
default_configobjectNoDefault values for config properties
allowed_content_typesarrayNoContent types where this element can be used (omit for all types)
supported_settingsarrayNoWhich standard section settings to expose in the editor

Response

json
{
  "success": true,
  "data": {
    "id": "pel_00000k1L2m3N4o5",
    "platform_key": "ecom360",
    "element_key": "popular-sale-items",
    "display_name": "Popular Sale Items",
    "description": "Displays a carousel of current popular/sale items",
    "icon": "ShoppingBagIcon",
    "category": "commerce",
    "config_schema": {
      "type": "object",
      "properties": {
        "max_items": {
          "type": "integer",
          "default": 12,
          "minimum": 1,
          "maximum": 50
        },
        "layout": {
          "type": "string",
          "enum": ["carousel", "grid"],
          "default": "carousel"
        }
      }
    },
    "default_config": {
      "max_items": 12,
      "layout": "carousel"
    },
    "allowed_content_types": ["homepage", "landing"],
    "supported_settings": ["padding", "max_width"],
    "is_active": true,
    "created_at": "2026-03-01T12:00:00+00:00",
    "updated_at": "2026-03-01T12:00:00+00:00"
  }
}

Unique Constraint

The combination of platform_key and element_key must be unique. Attempting to register a duplicate returns a 422 validation error.


Management API

Endpoints

MethodEndpointDescription
GET/api/v1/content/platform-elementsList all platform elements
GET/api/v1/content/platform-elements/activeList active elements (lightweight)
POST/api/v1/content/platform-elementsRegister a new element
GET/api/v1/content/platform-elements/{id}Get a single element
PUT/api/v1/content/platform-elements/{id}Update an element
DELETE/api/v1/content/platform-elements/{id}Delete an element

List Platform Elements

Required scope: engagehq:platform_elements.view

http
GET /api/v1/content/platform-elements

Query Parameters

ParameterTypeDefaultDescription
platform_keystring-Filter by platform (e.g., ecom360)
content_typestring-Filter by allowed content type (e.g., homepage)
is_activeboolean-Filter by active status
per_pageinteger20Items per page (1-100)
pageinteger1Page number

Example Request

javascript
const response = await fetch(
  'https://cdn.engagehq.retailsuccessplatform.com/api/v1/content/platform-elements?platform_key=ecom360',
  {
    headers: {
      'Authorization': `Bearer ${token}`,
      'X-Organization-Context': organizationId,
    },
  }
);

Example Response

json
{
  "success": true,
  "data": [
    {
      "id": "pel_00000k1L2m3N4o5",
      "platform_key": "ecom360",
      "element_key": "popular-sale-items",
      "display_name": "Popular Sale Items",
      "description": "Displays a carousel of current popular/sale items",
      "icon": "ShoppingBagIcon",
      "category": "commerce",
      "config_schema": { "..." : "..." },
      "default_config": { "max_items": 12, "layout": "carousel" },
      "allowed_content_types": ["homepage", "landing"],
      "supported_settings": ["padding", "max_width"],
      "is_active": true,
      "created_at": "2026-03-01T12:00:00+00:00",
      "updated_at": "2026-03-01T12:00:00+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 20,
    "total": 1
  }
}

List Active Elements (Lightweight)

Required scope: engagehq:platform_elements.view

Returns only active elements with minimal fields. Useful for populating the content builder palette without fetching full schemas.

http
GET /api/v1/content/platform-elements/active

Show Platform Element

Required scope: engagehq:platform_elements.view

http
GET /api/v1/content/platform-elements/{id}

Path Parameters

ParameterTypeDescription
idstringPlatform element hashkey (pel_xxxxx)

Update Platform Element

Required scope: engagehq:platform_elements.update

http
PUT /api/v1/content/platform-elements/{id}

Accepts the same fields as the registration endpoint. Only included fields are updated.

Example Request

javascript
const response = await fetch(
  `https://cdn.engagehq.retailsuccessplatform.com/api/v1/content/platform-elements/${elementId}`,
  {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${token}`,
      'X-Organization-Context': organizationId,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      display_name: 'Top Sale Items',
      default_config: { max_items: 8, layout: 'grid' },
    }),
  }
);

Delete Platform Element

Required scope: engagehq:platform_elements.delete

http
DELETE /api/v1/content/platform-elements/{id}

Deletion Protection

A platform element cannot be deleted if it is currently referenced by any published content item. The API returns a 409 Conflict response listing the content items that reference the element. You must remove the element from all content before deleting it.

Error Response (In Use)

json
{
  "success": false,
  "message": "Cannot delete platform element: it is referenced by 3 published content items.",
  "errors": {
    "references": [
      { "content_id": "con_00000a1B2c3D4e5", "title": "Summer Homepage" },
      { "content_id": "con_00000f6G7h8I9j0", "title": "Fall Landing Page" }
    ]
  }
}

Config Schema

The config_schema field accepts a standard JSON Schema object that defines editor-configurable properties for the element. The content builder renders form controls based on this schema.

Zero-Config Element

Elements that require no editor configuration can omit config_schema entirely. The element will appear in the builder with no configuration panel.

json
{
  "platform_key": "ecom360",
  "element_key": "store-locator-map",
  "display_name": "Store Locator Map",
  "description": "Embeds the interactive store locator map"
}

Configurable Element

Define properties in config_schema to give content editors control over the element's behavior:

json
{
  "platform_key": "ecom360",
  "element_key": "product-carousel",
  "display_name": "Product Carousel",
  "config_schema": {
    "type": "object",
    "properties": {
      "category_id": {
        "type": "string",
        "title": "Category",
        "description": "Filter products by category"
      },
      "max_items": {
        "type": "integer",
        "title": "Max Items",
        "default": 12,
        "minimum": 1,
        "maximum": 50
      },
      "layout": {
        "type": "string",
        "title": "Layout",
        "enum": ["carousel", "grid", "list"],
        "default": "carousel"
      },
      "show_prices": {
        "type": "boolean",
        "title": "Show Prices",
        "default": true
      }
    }
  },
  "default_config": {
    "max_items": 12,
    "layout": "carousel",
    "show_prices": true
  }
}

Supported Schema Types

JSON Schema TypeEditor Control
stringText input
string + enumDropdown select
string + format: "color"Color picker (swatch + hex input)
integer / numberNumber input (with minimum/maximum)
booleanToggle switch
object + format: "image"Media library image picker
array + itemsRepeatable item list (add/remove/reorder)

Array Fields (Repeatable Items)

Array fields render as a repeatable list with add, remove, and reorder controls. Each item's sub-properties are rendered using the same type rules above.

json
{
  "config_schema": {
    "type": "object",
    "properties": {
      "heading": {
        "type": "string",
        "description": "Section heading displayed above the grid."
      },
      "items": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "image": {
              "type": "object",
              "format": "image",
              "description": "Card image."
            },
            "title": {
              "type": "string",
              "description": "Card title."
            },
            "cta_url": {
              "type": "string",
              "description": "Button link URL."
            },
            "background_color": {
              "type": "string",
              "format": "color",
              "description": "Card background color."
            }
          }
        }
      }
    }
  }
}

Image Fields

Use "format": "image" on an object type to render the media library picker. The stored value is a media object with URLs, alt text, and dimensions:

json
{
  "url": "https://cdn.example.com/image.jpg",
  "urls": {
    "thumbnail": "https://cdn.example.com/image-thumb.jpg",
    "original": "https://cdn.example.com/image.jpg"
  },
  "alt_text": "Description of the image",
  "size": 245760,
  "dimensions": { "width": 1200, "height": 800 }
}

Color Fields

Use "format": "color" on a string type to render a color picker. The stored value is a hex color string (e.g., #ff6600).

Schema Validation

Config values are validated against config_schema when content is saved. Invalid values are rejected with a 422 validation error.


Allowed Content Types

The allowed_content_types array restricts which content types can use this element. When omitted, the element is available in all section-based content types.

Content TypeDescription
pageStatic pages
articleBlog posts and articles
landingLanding pages
homepageHomepages
json
{
  "allowed_content_types": ["homepage", "landing"]
}

In this example, the element only appears in the content builder when editing a homepage or landing page.


Supported Settings

The supported_settings array controls which standard section settings are exposed in the content builder when this element is used. This gives editors the same visual controls they have for built-in sections.

Available Settings

SettingDescription
paddingVertical padding (none, small, medium, large)
background_colorSection background color (hex, rendered as color picker)
max_widthContent max width (narrow, medium, wide, full)
anchor_idHTML anchor ID for in-page navigation
visibilityShow/hide toggle for the section
css_classAdditional CSS class names applied to the section wrapper
marginVertical margin (none, small, medium, large)
json
{
  "supported_settings": ["padding", "background_color", "max_width", "anchor_id"]
}

When omitted, no standard settings are exposed. The element relies entirely on its own config for customization.

Settings vs Config

Settings are standard visual controls shared with built-in sections (padding, width, etc.). Config is element-specific data defined by config_schema (max items, layout mode, category filter, etc.). Both are stored on the section and delivered via the Content API.


Content Storage Format

When a platform element is added to a content item, it is stored in the content.sections array alongside built-in sections. Platform elements are identified by type: "platform_element" and include a source: "platform" marker.

json
{
  "content": {
    "sections": [
      {
        "id": "section_1711234567_xyz789abc",
        "type": "hero",
        "content": {
          "headline": "Welcome to our store"
        },
        "settings": {
          "padding": "large"
        }
      },
      {
        "id": "section_1711234567_abc123def",
        "type": "platform_element",
        "source": "platform",
        "platform_key": "ecom360",
        "element_key": "popular-sale-items",
        "content": {},
        "config": {
          "max_items": 12,
          "layout": "carousel"
        },
        "settings": {
          "anchor_id": "",
          "padding": "medium"
        }
      },
      {
        "id": "section_1711234567_def456ghi",
        "type": "content",
        "content": {
          "headline": "About Us",
          "body": "<p>Learn more about our story...</p>"
        },
        "settings": {
          "padding": "medium"
        }
      }
    ]
  }
}

Platform Element Section Fields

FieldTypeDescription
idstringSection ID (section_{timestamp}_{random})
typestringAlways "platform_element"
sourcestringAlways "platform"
platform_keystringThe platform that owns this element (e.g., ecom360)
element_keystringThe specific element identifier (e.g., popular-sale-items)
contentobjectReserved for future use (currently empty {})
configobjectEditor-configured values from config_schema
settingsobjectStandard section settings (only those in supported_settings)

Rendering

Platform elements appear in the sections array in their authored order, interleaved with built-in sections. Your renderer should check section.type and delegate to the appropriate component. See JavaScript, Vue, and React examples.


Changelog
DateChange
2026-03-26Added array, format: "image", and format: "color" config schema types. Added visibility, css_class, and margin supported settings.
2026-03-24Initial publication.

EngageHQ Public Content Delivery API