# Synchronization Methods

## Introduction

Event synchronization allows menta tech to understand your inventory to enable resale. There are different methods to achieve this synchronization, depending on your platform's technical capabilities.

Regardless of the chosen method, the information structure (how you define tickets and prices) is critical. Consult the **[Data Structure](/en/guides/infoStructure)** guide to understand how to model your inventory correctly.

## Integration Options

{% table highlight-first=true highlight-row=3 %}
| Option | Description | When it makes sense | Benefits | Limitations |
|--------|-------------|----------------------|------------|--------------|
| Using the menta tech API | The platform sends CREATE/UPDATE requests directly to menta | When real-time sync and accuracy matter | Near real-time updates, no polling, most scalable option | Requires emitting outbound updates from the backend |
| Event endpoint exposed by the platform (recommended) | menta tech periodically queries an event endpoint from the ticketing platform | When an event endpoint already exists or a pull model is preferred | Easy adoption; the platform controls structure and frequency; menta manages the synchronization | Data can become stale; polling adds load and isn’t ideal for frequent changes |
| Manual event upload | Events are created manually, without APIs | For pilots or low-volume partners | No development, fastest time to production | Not scalable; manual operations; higher risk of stale data |
{% /table %}

{% conditionaltabs id="tabs-1765309889524" %}

{% tab label="menta tech API" %}
## Sending via API (Push)

Use this method when your backend can emit updates in real time. Your backend acts as the source of truth and notifies menta whenever there are changes.

### Implementation

You must send requests to our API whenever an event is created, updated, or canceled.

```bash
POST /v1/events
```

The request body (JSON) will depend on the data model you choose (Standard, Simple Price, or Advanced). **Review the [Data Structure](/en/guides/infoStructure)** guide to see the required JSON schemas.

Useful links:
- <a href='https://connect.mentatech.io/es/api/post-events' target="_blank">Create event (API Reference)</a>
- <a href='https://connect.mentatech.io/es/api/put-events' target="_blank">Update event (API Reference)</a>
{% /tab %}

{% tab label="Endpoint exposed by your platform" %}
## Pull Endpoint

This is the recommended integration method: your platform exposes a public URL (e.g., `https://api.yourplatform.com/menta-feed`) and menta tech queries it periodically to fetch updates — you control the endpoint and menta takes care of the synchronization.

### Endpoint Requirements

The endpoint must return a JSON with the list of active events (an array of objects). Each event carries its show with the venue (`location`), images, lifecycle dates, and the ticket structure expressed as **combinations**.

### Required JSON structure

Below is an example of how the event array returned by your endpoint should look:

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

{% column width="1" valign="top" %}
**Key fields:**
- **Root Array**: The response must be a list `[...]` with one entry per active event.
- **Event**: `title`, `description`, `externalReferenceId` (your stable id for the event — never reused or mutated) and, optionally, `producers` (contact information).
- **Show** (`shows`): `title`, `showId` (your stable id for the show), `status` (your platform's native show status — e.g. `ON_SALE`, `CANCELLED`), `dates` (ISO 8601 with timezone: `startsAt`, `salesStartAt`, `salesEndAt`, `publicAt`), `location` (`address`, `city`, `state`, `postalCode`, `country` and, optionally, `venueName`), `images` (at least one `main` image), and optionally `primarySalesUrl` and `tags` (`"key:value"` strings).
- **combinations**: one entry per existing combination of data-field values in your admin — every leaf of your ticket-structure tree. Each combination carries:
  - `values`: one `{ valueId, fieldTitle, value }` entry per data field. `fieldTitle` is the label of the field as typed in your admin, `value` is the option as typed, and `valueId` is your stable id for that value (persists across renames).
  - `price` (face value, **excluding commissions and fees**) and `currency` (ISO 4217).
  - `stock`: `{ total, remaining }`, or `null` when the combination has no fixed quota.
  - `webVisibility` (send `false` when the combination is paused or hidden) and `webSoldOut` (send `true` when fully sold).
  - `attendeeQuestions` *(optional)*: per-ticket checkout questions for this combination (see below).
- **buyerQuestions** *(optional, show level)*: per-order checkout questions (see below).
{% /column %}

{% column width="1" valign="top" %}
```json
[
  {
    "title": "Example Concert",
    "description": "Example event description.",
    "externalReferenceId": "evt_example_001",
    "producers": [
      {
        "name": "Example Producer",
        "emails": ["contact@example-producer.com"],
        "producerId": "prod_001"
      }
    ],
    "shows": {
      "title": "Example Concert - Main Show",
      "dates": {
        "startsAt": "2025-12-15T20:00:00.000-03:00",
        "salesStartAt": "2025-10-01T10:00:00.000-03:00",
        "salesEndAt": "2025-12-15T18:00:00.000-03:00",
        "publicAt": "2025-09-15T00:00:00.000-03:00"
      },
      "showId": "show_example_001",
      "status": "ON_SALE",
      "location": {
        "address": "Example Ave 1234",
        "city": "Buenos Aires",
        "state": "Buenos Aires",
        "postalCode": "1425",
        "country": "Argentina",
        "venueName": "Example Stadium"
      },
      "images": [
        { "url": "https://example.com/images/main-event.jpg", "kind": "main" }
      ],
      "primarySalesUrl": "https://yourplatform.com/event/example-concert/show/001",
      "tags": ["genre:rock", "tour:2025"],
      "combinations": [
        {
          "values": [
            { "valueId": "v_cat_general", "fieldTitle": "Category", "value": "General" },
            { "valueId": "v_tar_adult", "fieldTitle": "Tariff", "value": "Adult" }
          ],
          "price": 100,
          "currency": "USD",
          "stock": { "total": 500, "remaining": 380 },
          "webVisibility": true,
          "webSoldOut": false
        },
        {
          "values": [
            { "valueId": "v_cat_general", "fieldTitle": "Category", "value": "General" },
            { "valueId": "v_tar_special", "fieldTitle": "Tariff", "value": "Special Discount" }
          ],
          "price": 70,
          "currency": "USD",
          "stock": { "total": 500, "remaining": 470 },
          "webVisibility": true,
          "webSoldOut": false
        },
        {
          "values": [
            { "valueId": "v_cat_vip", "fieldTitle": "Category", "value": "VIP" },
            { "valueId": "v_tar_adult", "fieldTitle": "Tariff", "value": "Adult" }
          ],
          "price": 250,
          "currency": "USD",
          "stock": null,
          "webVisibility": true,
          "webSoldOut": false
        }
      ]
    }
  }
]
```
{% /column %}
{% /columns %}

{% callout type="warning" title="Combinations are the source of truth" %}
menta does not derive or invent combinations: **only the combinations you send exist**. Send one entry per sellable leaf of your ticket structure, whatever your data fields are called. Each combination is uniquely identified by the set of `valueId`s it carries — no separate combination id is required — so `externalReferenceId`, `showId` and every `valueId` must be **stable ids** that persist across renames and are never reused.
{% /callout %}

{% callout type="info" title="Prices without commissions or fees" %}
`combination.price` is the **face value**: the price of that combination as you actually charge it, without service fees or additional taxes you may add at primary checkout.
{% /callout %}

### Buyer and attendee questions

If your checkout collects custom information (a date of birth, a student-card ID, a t-shirt size), send the question definitions in the payload and menta collects the same answers from the resale buyer and returns them to you in the ownership-change webhook:

- **`buyerQuestions`** *(show level)*: asked once per order. They do not vary by category.
- **`attendeeQuestions`** *(inside each combination)*: asked once per ticket, so they can differ per category. When the same question applies to several combinations, repeat it in each one keeping the same `questionId`.

A free-entry question, optionally constrained via `validator` (`{ regex }` for text/textarea/email/number, `{ min, max }` for date/time/number):

```json
{ "questionId": "q_birthdate", "title": "Date of birth", "type": "date", "required": true,
  "validator": { "min": "1900-01-01", "max": "2008-06-29" } }
```

An option-based question (`single_select` = pick one, `multi_select` = pick several; `optionId` is stable, `value` is the displayed label):

```json
{ "questionId": "q_tshirt", "title": "T-shirt size", "type": "single_select", "required": true,
  "options": [ { "optionId": "s", "value": "S" }, { "optionId": "m", "value": "M" }, { "optionId": "l", "value": "L" } ] }
```

`type` is one of `text`, `textarea`, `email`, `number`, `date`, `time` (free-entry) or `single_select` / `multi_select` (option-based). `questionId` is your stable id — it persists across renames and is the key menta uses to map each answer back to its question. When `required` is `true`, menta blocks checkout until the buyer answers. menta renders **only** the questions you send: omit any question that should not be shown to the resale buyer.
{% /tab %}

{% tab label="Manual event upload" %}
## Manual upload

For low volumes or pilot tests, it is possible to upload events via files (CSV/Excel) processed by menta's operations team.

This method requires no development but has significant operational limitations and risk of data staleness. Contact your account manager if you wish to use this option.
{% /tab %}
{% /conditionaltabs %}

---

## Show Status

Each show includes a `status` field that represents its current lifecycle state. This status determines how the show is displayed and whether resale activity is allowed.

{% table highlight-first=true %}
| Status | Description | Visible to public | Resale enabled |
| :--- | :--- | :--- | :--- |
| `ON_SALE` | Tickets are actively being sold in the primary market. The show is publicly visible and resale is fully operational. | Yes | Yes |
| `ANNOUNCED` | The show has been publicly announced and is visible, but primary ticket sales have not started yet or have been paused. Users can see the event but cannot purchase tickets in the primary market. Resale may still be active if tickets were previously distributed. | Yes | Depends on configuration |
| `CANCELLED` | The show has been cancelled. No further sales or resale activity is allowed. Existing resale listings are removed and pending transactions are handled according to the cancellation policy. | Yes (marked as cancelled) | No |
| `RESCHEDULED` | The show has been moved to a new date or time. The `dates.startsAt` field reflects the updated schedule. Resale activity may continue under the new date depending on configuration. | Yes (marked as rescheduled) | Depends on configuration |
| `HIDDEN` | The show is not visible to the public. It does not appear in search results, event listings, or the resale marketplace. Typically used for shows that are being set up or temporarily removed. | No | No |
| `PRIVATE` | The show is restricted to a specific audience (e.g., invite-only, presale groups, or internal events). It is not visible in public listings but may be accessible via direct link or access code. | Only with direct access | Depends on configuration |
{% /table %}

{% callout type="info" title="Status and dates" %}
The `status` field reflects the **current operational state** of the show, while the `dates` object provides the **scheduled timeline**. For example, a show can have `status: "ANNOUNCED"` with a future `dates.salesStartAt` — meaning it will automatically transition to on-sale at that date. Always send both fields so menta tech can manage the show lifecycle accurately.
{% /callout %}

## Show Dates

The `dates` object groups all relevant dates for a show's lifecycle. All dates must be in ISO 8601 format.

{% table highlight-first=true %}
| Field | Description |
| :--- | :--- |
| `dates.startsAt` | Date and time when the show begins (the performance start time). This is the main reference date for the event. |
| `dates.salesStartAt` | Date and time when primary ticket sales open. Before this date, tickets cannot be purchased in the primary market. |
| `dates.salesEndAt` | Date and time when primary ticket sales close. After this date, tickets are no longer available in the primary market. |
| `dates.publicAt` | Date and time when the show becomes publicly visible on the web. Before this date, the show may exist internally but is not displayed to end users. |
{% /table %}

---

## Event Cancellation

{% callout type="warning" title="Critical importance" %}
**It is essential to notify menta tech when an event is cancelled.** Payment distribution to resale ticket sellers occurs a few days after the original event date. If an event is cancelled and menta is not notified, payments will be processed normally after the scheduled date and **there will be no way to recover the money** once distributed.
{% /callout %}

### Why is this so important?

When an event is cancelled:
1. **Resale buyers must be refunded** - menta automatically handles refunds if the cancellation is notified in time.
2. **Payments to sellers are stopped** - if the cancellation is not reported, sellers will receive payment as if the event had taken place.
3. **No post-distribution recovery** - once funds are distributed, transactions cannot be reversed.

### How to notify a cancellation

{% conditionaltabs id="tabs-cancellation" %}

{% tab label="menta tech API" %}
### Cancellation via API (Recommended)

To cancel an event through the API, use the cancellation endpoint:

```bash
POST /v1/events/:externalReferenceId/cancellation
```

Where `:externalReferenceId` is the unique identifier of the event in your ticketing system.

**Optional parameters:**
- `showId`: If you only want to cancel a specific show within the event, include this parameter in the query string.

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

{% /tab %}

{% tab label="Endpoint exposed by your platform" %}
### Cancellation with Pull integration

If your integration is through an endpoint that menta queries periodically, you have two options:

**Option 1: Cancelled events feed**
Expose an additional endpoint (e.g., `https://api.yourplatform.com/menta-feed/cancelled`) that returns the list of cancelled events. menta will query this feed periodically.

```json
[
  {
    "externalReferenceId": "evt_example_001",
    "cancelledAt": "2025-01-15T10:30:00.000Z",
    "showId": "show_001" // optional, if only one show
  }
]
```

**Option 2: Direct API Call (Recommended)**
Even if your main integration is through pull, **we recommend using the cancellation API call** for real-time notifications:

```bash
POST /v1/events/:externalReferenceId/cancellation
```

This ensures the cancellation is processed immediately without waiting for the next polling cycle.
{% /tab %}

{% tab label="Manual event upload" %}
### Cancellation with manual upload

For manual upload integrations, you have two options:

**Option 1: API Call (Recommended)**
Even if event uploads are manual, we recommend implementing the cancellation API call:

```bash
POST /v1/events/:externalReferenceId/cancellation
```

**Option 2: Notification to Account Manager**
Since this type of integration is oriented towards lower-volume platforms, it is also possible to inform the cancellation directly to your account manager. However, this may cause delays in processing.

{% callout type="info" %}
Contact your account manager as soon as possible when an event is cancelled to avoid incorrect payments.
{% /callout %}
{% /tab %}

{% /conditionaltabs %}
