# Information Structure

## Introduction

To enable resale, menta tech needs a structured representation of your events. This guide details the data hierarchy and available models to represent your inventory, regardless of the synchronization method you use.

{% callout type="info" title="Two sync methods: PUSH and PULL" %}
The **data structure defined in this guide applies to both** sync methods with menta tech:

- **PUSH** — Your backend sends requests to menta's API (`POST /v1/events`, `POST /v1/events/rules`) whenever there are changes. Recommended for near real-time integrations.
- **PULL** — Your platform exposes a public endpoint and menta polls it periodically. The information travels inside the same event JSON (see [Synchronization Methods](/en/guides/eventData)).

What changes between them is the **transport**, not the concepts: `ticketOption`, `priceType`, and `combinations` are defined the same way in both. Below, inside each model (Standard and Price Detail), you'll find the concrete implementation for each method.
{% /callout %}

## Data Hierarchy

The base structure connects events, performances, and access categories.

{% columns gap="2rem" align="start" %}

{% column width="1" valign="center" %}
{% diagram type="erd" height="500px" title="Data Structure" %}
{
  "nodes": [
    {
      "id": "node1",
      "type": "custom",
      "position": { "x": 88, "y": 86 },
      "data": {
        "label": "Event",
        "subtitle": "id, title, producer",
        "background": "#ffffff"
      }
    },
    {
      "id": "node-shows",
      "type": "custom",
      "position": { "x": 84, "y": 238 },
      "data": {
        "label": "Shows",
        "subtitle": "showId, date, title",
        "background": "#fff3e0"
      }
    },
    {
      "id": "node-ticketA",
      "type": "custom",
      "position": { "x": -21, "y": 365 },
      "data": {
        "label": "ticketOption A",
        "subtitle": "General Admission, id",
        "background": "#e3f2fd"
      }
    },
    {
      "id": "node-ticketB",
      "type": "custom",
      "position": { "x": 198, "y": 364 },
      "data": {
        "label": "ticketOption B",
        "subtitle": "VIP Access, id",
        "background": "#e3f2fd"
      }
    }
  ],
  "edges": [
    {
      "id": "edge-1",
      "source": "node1",
      "target": "node-shows",
      "label": "has one or more",
      "animated": false
    },
    {
      "id": "edge-2",
      "source": "node-shows",
      "target": "node-ticketA",
      "animated": true
    },
    {
      "id": "edge-3",
      "source": "node-shows",
      "target": "node-ticketB",
      "animated": true
    }
  ]
}
{% /diagram %}
{% /column %}

{% column width="1" valign="center" %}

This hierarchy allows menta to:
- **Validate tickets**: Confirm eligibility based on event and show.
- **Generate UI**: Display categories and maps correctly.
- **Apply rules**: Configure resale at the event, show, or category level.

The critical point is how you define **access categories** (ticketOptions) and their prices.

{% /column %}
{% /columns %}

## Pricing and Inventory Modeling

Two dimensions define your inventory structure:

- **ticketOption**: the access category (GA, VIP). This is what the resale buyer **sees and chooses**. It carries its own `price` (category price **excluding commissions and fees**) and optionally an `area` (zone grouping — multiple ticketOptions can share the same `area`, e.g., `Upper Grandstand VIP` and `Upper Grandstand Regular` with `"area": "Upper Grandstand"`).
- **priceType**: the commercial variation (Pre-sale, Early Bird). This is internal metadata.
- **combination** (when priceTypes exist): the `ticketOption` + `priceType` pair that actually sells. It carries its own `price` (also **without commissions or fees**) and, optionally, a `description`. **The combination price takes precedence** over the price declared on the associated ticketOption.

### Why separate them?

Mixing both concepts (e.g., "GA Pre-sale" and "GA Regular" as distinct categories) fragments inventory and confuses buyers. Separating them groups all "GA" inventory together, regardless of the original price.

menta offers two integration models to handle this:

## Comparative Table

{% table highlight-first=true %}
| Model | What you send | How menta interprets the data | When it makes sense | Benefits | Limitations |
|--------|------------|--------------------------------|----------------------|------------|--------------|
| Standard | Only ticketOptions | A unified category by access type | When there are no price variations within the access | Simplest integration, minimal configuration | Does not distinguish price differences, limited grouping and filters |
| Price Detail | ticketOptions + priceTypes + real combinations | Only explicitly created combinations exist | When maximum control and precision is needed | Dashboard reflects your catalog exactly, ideal for advanced pricing | Requires maintaining combinations via API |
{% /table %}

{% conditionaltabs id="tabs-1765310713135" %}
{% tab label="Standard" %}
## Standard

{% columns gap="2rem" align="start" %}
{% column width="1" %}
### General Description

In the Standard model, your platform sends only ticketOptions. menta assumes that each ticketOption represents a unique product without internal price variations.

### Implementation

You send only the `ticketOptions`. There's no need to declare `priceTypes` or combinations. The transport changes depending on the sync method you use.
{% /column %}

{% column width="1" valign="center" %}
{% diagram type="erd" height="200px" title="Standard Flow" %}
{
  "nodes": [
    { "id": "in", "type": "custom", "position": { "x": 20, "y": 75 }, "data": { "label": "TicketOption", "subtitle": "GA", "background": "#e3f2fd" } },
    { "id": "out", "type": "custom", "position": { "x": 400, "y": 75 }, "data": { "label": "Final Product", "subtitle": "GA", "background": "#e8f5e9" } }
  ],
  "edges": [
    { "id": "e1", "source": "in", "target": "out", "label": "becomes", "animated": true, "style": { "stroke": "#4caf50" } }
  ]
}
{% /diagram %}
{% /column %}
{% /columns %}

#### Option A — PUSH (menta API)

A single API call to `POST /v1/events` sending only the `ticketOptions` within each show.

{% apiembed endpoint="post-events" show="link" width="auto" /%}

{% columns gap="2rem" align="center" %}

{% column width="0.5" valign="center" %}
{% callout type="info" title="Request structure" %}
In the Standard model, you only send ticketOptions without priceTypes information. menta tech will treat each ticketOption as a unique category without price variations.
{% /callout %}

<br>

```json
{
  "externalReferenceId": "event-123",
  "shows": {
    "showId": "show-456",
    "ticketOptions": [
      {
        "title": "General Admission",
        "ticketId": "general-admission",
        "description": "General field access",
        "currency": "USD",
        "price": 100,
        "area": "Field"
      },
      {
        "title": "VIP",
        "ticketId": "vip",
        "description": "VIP access with exclusive benefits",
        "currency": "USD",
        "price": 250,
        "area": "Grandstand"
      }
    ]
  }
}
```
{% /column %}

{% column width="0.5" valign="center" sticky=true %}

{% codeannotation highlight-lines="2" %}
**externalReferenceId**: Unique identifier of the event in your platform. Used for all future references.
{% /codeannotation %}

{% codeannotation highlight-lines="4" %}
**showId**: Unique identifier of the show in your system.
{% /codeannotation %}

{% codeannotation highlight-lines="5" %}
**ticketOptions**: Array with available access categories. You only send ticketOptions, without priceTypes.
{% /codeannotation %}

{% codeannotation highlight-lines="7" %}
**title**: Visible name of the category for the resale buyer.
{% /codeannotation %}

{% codeannotation highlight-lines="8" %}
**ticketId**: Unique identifier of the access category in your system (equivalent to ticketOptionId).
{% /codeannotation %}

{% codeannotation highlight-lines="9" %}
**description**: Description of the access category.
{% /codeannotation %}

{% codeannotation highlight-lines="10" %}
**currency**: Currency of the ticket price.
{% /codeannotation %}

{% codeannotation highlight-lines="11" %}
**price**: Category price **excluding commissions and fees**.
{% /codeannotation %}

{% codeannotation highlight-lines="12" %}
**area** *(optional)*: Zone grouping. Multiple ticketOptions can share the same value (e.g., `Upper Grandstand VIP` and `Upper Grandstand Regular` with `"area": "Upper Grandstand"`).
{% /codeannotation %}

{% /column %}
{% /columns %}

#### Option B — PULL (Exposed Endpoint)

In the JSON returned by your endpoint (e.g., `https://api.yourplatform.com/menta-feed`), within each show include only the `ticketOptions` array. Do not add `priceTypes` or `combinations`: by omitting them, menta treats the show under the Standard model.

See the **[Synchronization Methods](/en/guides/eventData)** guide for the full endpoint structure (location, producers, shows, etc.).

```json
{
  "externalReferenceId": "event-123",
  "shows": [
    {
      "showId": "show-456",
      "status": "ON_SALE",
      "dates": { "startsAt": "2025-12-15T20:00:00.000-03:00" },
      "ticketOptions": [
        {
          "title": "General Admission",
          "ticketId": "general-admission",
          "description": "General field access",
          "currency": "USD",
          "price": 100,
          "area": "Field"
        },
        {
          "title": "VIP",
          "ticketId": "vip",
          "description": "VIP access with exclusive benefits",
          "currency": "USD",
          "price": 250,
          "area": "Grandstand"
        }
      ]
    }
  ]
}
```

### When this model makes sense

- Your events do not use multiple price categories within the same access type
- You seek the simplest possible integration
- You don't need grouping, filtering, or alerts based on price

### Benefits

- Lower implementation effort
- Very simple rule configuration, one rule per ticketOption
- No need to manage priceTypes or combinations

### Limitations

- If multiple internal prices exist, the buyer will not see significant groupings
- All tickets of the same access look identical in resale even if they were purchased under different conditions
- No support for alerts or filters beyond the ticketOption itself
{% /tab %}
{% tab label="Price Detail" %}
## Price Detail

{% columns gap="2rem" align="start" %}
{% column width="1" %}
### General Description

In the Price Detail model, your platform sends `ticketOptions` and `priceTypes`, and you also explicitly define only the real combinations that exist in your catalog using the `POST /v1/events/rules` endpoint with `ruleType: COMBINATION`.

menta tech **does not generate combinations automatically**. Only the combinations you explicitly define will exist.

### Implementation

On top of `ticketOptions`, you declare available `priceTypes` and the **real combinations** that exist in your catalog. The transport changes depending on the sync method you use.
{% /column %}

{% column width="1" valign="center" %}
{% diagram type="erd" height="350px" title="Explicit Combination" %}
{
  "nodes": [
    {
      "id": "to",
      "type": "custom",
      "position": {
        "x": 692.3844155844157,
        "y": 94.04220779220779
      },
      "data": {
        "label": "TicketOption",
        "subtitle": "VIP",
        "background": "#e3f2fd"
      }
    },
    {
      "id": "pt1",
      "type": "custom",
      "position": {
        "x": 960.9032467532467,
        "y": 94.04220779220779
      },
      "data": {
        "label": "PriceType",
        "subtitle": "Presale",
        "background": "#f3e5f5"
      }
    },
    {
      "id": "pt2",
      "type": "custom",
      "position": {
        "x": 414.7551948051948,
        "y": 94.04220779220779
      },
      "data": {
        "label": "PriceType",
        "subtitle": "Regular",
        "background": "#f3e5f5"
      }
    },
    {
      "id": "blocked",
      "type": "custom",
      "position": {
        "x": 808.6194805194805,
        "y": 250
      },
      "data": {
        "label": "Not Generated",
        "subtitle": "No explicit rule",
        "background": "#ffebee"
      }
    },
    {
      "id": "res2",
      "type": "custom",
      "position": {
        "x": 578.8194805194805,
        "y": 250
      },
      "data": {
        "label": "Product",
        "subtitle": "VIP + Regular",
        "background": "#e8f5e9"
      }
    }
  ],
  "edges": [
    {
      "id": "e_b1",
      "source": "to",
      "target": "blocked",
      "animated": false,
      "style": {
        "stroke": "#e57373",
        "strokeDasharray": "5,5"
      },
      "markerEnd": {
        "type": "arrowclosed",
        "color": "#9ca3af",
        "width": 16,
        "height": 16
      }
    },
    {
      "id": "e_b2",
      "source": "pt1",
      "target": "blocked",
      "animated": false,
      "style": {
        "stroke": "#e57373",
        "strokeDasharray": "5,5"
      },
      "markerEnd": {
        "type": "arrowclosed",
        "color": "#9ca3af",
        "width": 16,
        "height": 16
      }
    },
    {
      "id": "e2",
      "source": "to",
      "target": "res2",
      "animated": true,
      "markerEnd": {
        "type": "arrowclosed",
        "color": "#9ca3af",
        "width": 16,
        "height": 16
      }
    },
    {
      "id": "e4",
      "source": "pt2",
      "target": "res2",
      "animated": true,
      "style": {
        "stroke": "#9c27b0"
      },
      "markerEnd": {
        "type": "arrowclosed",
        "color": "#9ca3af",
        "width": 16,
        "height": 16
      }
    }
  ]
}
{% /diagram %}
{% /column %}
{% /columns %}

#### Option A — PUSH (menta API)

Your platform makes **two sequential API calls**:

1. **Step 1** — Create the event with `ticketOptions` and `priceTypes` using `POST /v1/events`.
2. **Step 2** — Define the real combinations using `POST /v1/events/rules` with `ruleType: COMBINATION`.

##### Step 1: Create the event

First, you create the event by sending the base dimensions (ticketOptions and priceTypes):

{% apiembed endpoint="post-events" show="link" width="auto" /%}

{% columns gap="2rem" align="center" %}

{% column width="0.5" valign="center" %}
{% callout type="info" title="Request structure" %}
You send the ticketOptions and priceTypes available in your system. At this point, menta tech does not yet create combinations.
{% /callout %}

<br>

```json
{
  "externalReferenceId": "event-123",
  "shows": {
    "showId": "show-456",
    "ticketOptions": [
      {
        "title": "General Admission",
        "ticketId": "general-admission",
        "description": "General field access",
        "currency": "USD",
        "price": 100,
        "area": "Field"
      },
      {
        "title": "VIP",
        "ticketId": "vip",
        "description": "VIP access with exclusive benefits",
        "currency": "USD",
        "price": 250,
        "area": "Grandstand"
      }
    ],
    "priceTypes": [
      {
        "priceTypeId": "early-bird",
        "title": "Early Bird"
      },
      {
        "priceTypeId": "regular",
        "title": "Regular Price"
      }
    ]
  }
}
```
{% /column %}

{% column width="0.5" valign="center" sticky=true %}

{% codeannotation highlight-lines="2" %}
**externalReferenceId**: Unique identifier of the event in your platform. Will be used in the next step.
{% /codeannotation %}

{% codeannotation highlight-lines="4" %}
**showId**: Unique identifier of the show in your system. Will be used in the next step.
{% /codeannotation %}

{% codeannotation highlight-lines="5" %}
**ticketOptions**: Array with access categories available in your catalog.
{% /codeannotation %}

{% codeannotation highlight-lines="7" %}
**title**: Visible name of the category for the resale buyer.
{% /codeannotation %}

{% codeannotation highlight-lines="8" %}
**ticketId**: Unique identifier of the access category in your system (equivalent to ticketOptionId).
{% /codeannotation %}

{% codeannotation highlight-lines="11" %}
**price**: Category price **excluding commissions and fees**. If you declare `combinations`, the combination price takes precedence over this one.
{% /codeannotation %}

{% codeannotation highlight-lines="12" %}
**area** *(optional)*: Zone grouping. Multiple ticketOptions can share the same value.
{% /codeannotation %}

{% codeannotation highlight-lines="23" %}
**priceTypes**: Array with price types available in your system.
{% /codeannotation %}

{% codeannotation highlight-lines="25" %}
**priceTypeId**: Unique identifier of the price type in your system. Will be used in the next step.
{% /codeannotation %}

{% /column %}
{% /columns %}

##### Step 2: Define real combinations

Then, you explicitly define only the combinations that actually exist in your catalog:

{% apiembed endpoint="post-events-rules" show="link" width="auto" /%}

{% columns gap="2rem" align="center" %}

{% column width="0.5" valign="center" %}
{% callout type="info" title="Request structure" %}
You only define the combinations that actually exist in your system. menta tech will not generate combinations automatically. You must specify each valid combination using `ruleType: COMBINATION`.
{% /callout %}

<br>

```json
[
  {
    "externalReferenceEventId": "event-123",
    "showId": "show-456",
    "ticketOptionId": "general-admission",
    "priceTypeId": "early-bird",
    "ruleType": "COMBINATION",
    "price": 80,
    "description": "General Admission – Early Bird"
  },
  {
    "externalReferenceEventId": "event-123",
    "showId": "show-456",
    "ticketOptionId": "general-admission",
    "priceTypeId": "regular",
    "ruleType": "COMBINATION",
    "price": 100
  },
  {
    "externalReferenceEventId": "event-123",
    "showId": "show-456",
    "ticketOptionId": "vip",
    "priceTypeId": "early-bird",
    "ruleType": "COMBINATION",
    "price": 200
  }
]
```
{% /column %}

{% column width="0.5" valign="center" sticky=true %}

{% codeannotation highlight-lines="2" %}
The body is an array of objects, each representing a valid combination.
{% /codeannotation %}

{% codeannotation highlight-lines="4" %}
**externalReferenceEventId**: The unique identifier of the event (must match the one sent in Step 1).
{% /codeannotation %}

{% codeannotation highlight-lines="5" %}
**showId**: The unique identifier of the show (must match the one sent in Step 1).
{% /codeannotation %}

{% codeannotation highlight-lines="6" %}
**ticketOptionId**: Identifier of the access category for this combination (must match the `ticketId` sent in Step 1).
{% /codeannotation %}

{% codeannotation highlight-lines="7" %}
**priceTypeId**: Identifier of the price type for this combination (must match the one sent in Step 1).
{% /codeannotation %}

{% codeannotation highlight-lines="8" %}
**ruleType**: Must be `"COMBINATION"` to define valid combinations between ticketOption and priceType.
{% /codeannotation %}

{% codeannotation highlight-lines="9" %}
**price**: Combination price **excluding commissions and fees**. Takes precedence over the `price` declared on the associated ticketOption.
{% /codeannotation %}

{% codeannotation highlight-lines="10" %}
**description** *(optional)*: Free-form text describing the combination (e.g., a commercial or internal label).
{% /codeannotation %}

{% /column %}
{% /columns %}

**Important note**: Only the combinations you explicitly define in this second API call will appear in the dashboard and in the resale matrix. If you don't define a combination (for example, VIP with Regular Price), that combination will not exist in menta even though both dimensions are synchronized in Step 1.

#### Option B — PULL (Exposed Endpoint)

In the JSON returned by your endpoint, within each show include three arrays: `ticketOptions`, `priceTypes`, and `combinations`. **Everything travels in a single payload**, there are no two steps like in PUSH.

{% callout type="warning" title="Key PULL rule" %}
If you declare `priceTypes`, **it's mandatory** to include `combinations` listing all valid `ticketOption` + `priceType` pairs. menta tech does not generate combinations automatically; only those appearing in that array will exist.

If your catalog has no price variations, omit `priceTypes` and `combinations` and use the Standard model.
{% /callout %}

{% columns gap="2rem" align="center" %}

{% column width="0.5" valign="center" %}
```json
{
  "externalReferenceId": "event-123",
  "shows": [
    {
      "showId": "show-456",
      "status": "ON_SALE",
      "dates": { "startsAt": "2025-12-15T20:00:00.000-03:00" },
      "ticketOptions": [
        {
          "title": "General Admission",
          "ticketId": "general-admission",
          "description": "General field access",
          "currency": "USD",
          "price": 100,
          "area": "Field"
        },
        {
          "title": "VIP",
          "ticketId": "vip",
          "description": "VIP access with exclusive benefits",
          "currency": "USD",
          "price": 250,
          "area": "Grandstand"
        }
      ],
      "priceTypes": [
        {
          "priceTypeId": "early-bird",
          "title": "Early Bird"
        },
        {
          "priceTypeId": "regular",
          "title": "Regular Price"
        }
      ],
      "combinations": [
        {
          "ticketOptionId": "general-admission",
          "priceTypeId": "early-bird",
          "price": 80,
          "description": "General Admission – Early Bird"
        },
        {
          "ticketOptionId": "general-admission",
          "priceTypeId": "regular",
          "price": 100
        },
        {
          "ticketOptionId": "vip",
          "priceTypeId": "early-bird",
          "price": 200
        }
      ]
    }
  ]
}
```
{% /column %}

{% column width="0.5" valign="center" sticky=true %}

{% codeannotation highlight-lines="7" %}
**ticketOptions**: Access categories visible to the buyer. Each declares its `price` (without commissions or fees) and optionally an `area`.
{% /codeannotation %}

{% codeannotation highlight-lines="14" %}
**price** (ticketOption): Base category price **excluding commissions and fees**. When `combinations` are present, the combination price takes precedence over this one.
{% /codeannotation %}

{% codeannotation highlight-lines="15" %}
**area** *(optional)*: Zone grouping. Multiple ticketOptions can share the same value (e.g., `Upper Grandstand VIP` and `Upper Grandstand Regular` with `"area": "Upper Grandstand"`).
{% /codeannotation %}

{% codeannotation highlight-lines="25" %}
**priceTypes**: Price types available for sale (e.g., Adult, Special Discount, Early Bird). This is **optional**: omit this array if you have no internal price variations.
{% /codeannotation %}

{% codeannotation highlight-lines="35" %}
**combinations**: `ticketOption` + `priceType` pairs that actually exist in your catalog. If you send `priceTypes`, this array **is mandatory**. The `vip + regular` combination doesn't appear because it doesn't exist in the catalog, and therefore will not be generated in menta.
{% /codeannotation %}

{% codeannotation highlight-lines="39" %}
**price** (combination): Specific combination price, **without commissions or fees**.
{% /codeannotation %}

{% codeannotation highlight-lines="40" %}
**description** *(optional)*: Free-form text describing the combination.
{% /codeannotation %}

{% /column %}
{% /columns %}

See the **[Synchronization Methods](/en/guides/eventData)** guide for the full endpoint structure (location, producers, dates, etc.).

### When this model makes sense

- You need precise mapping between menta and your real catalog
- Not all ticketOptions combine with all priceTypes
- You want to avoid showing categories or combinations that don't exist in your primary system

### Benefits

- The dashboard reflects the real configuration of your events exactly
- No artificial or unused combinations appear
- Ideal for complex commercial strategies and large-scale events

### Limitations

- Requires managing combinations via API
- Must be updated whenever ticketOptions or priceTypes change
{% /tab %}
{% /conditionaltabs %}
