# Ticket Leads API (Market Data)

## Overview

The **Market Data Ticket Leads** feature allows you to send information about users who participate in the ticket lifecycle: users who purchased tickets in primary sales or had the intention to do so at some point. This data helps menta tech identify potential buyers for available resale tickets on your platform.

There are different types of leads we can receive based on user status:

- **Ticket Holder**: Users who have already purchased a ticket and are potential resale sellers
- **Abandoned Cart**: Users who abandoned their primary purchase and may be interested in resale
- **Virtual Queue**: Users who were in the virtual queue but didn't purchase, showing interest
- **Wishlist**: Users who subscribed to receive notifications about availability

---

## Lead Types Comparison

{% table highlight-first=true %}
| Type | Description | Purpose | When to Use | Benefits |
|------|-------------|---------|------------|----------|
| **Ticket Holder** | User with a purchased ticket | Potential resale seller | When a user purchases a ticket | User already owns the asset; higher resale probability |
| **Abandoned Cart** | User who abandoned primary purchase | Potential resale buyer | When a cart is abandoned | User showed interest but price/timing wasn't right |
| **Virtual Queue** | User abandoned from virtual queue | Potential resale buyer | When user leaves the queue | Confirmed interest; possible buyer with urgency |
| **Wishlist** | User subscribed for notifications | Lead for offer notification | When user subscribes | Explicit opt-in; high conversion probability |
{% /table %}

---

## Available Endpoints

There are two ways to send ticket leads:

1. **POST Individual**: To send a single lead
2. **POST Bulk/Batch**: To send multiple leads in a single call (up to 1000 per request)

---

## Endpoint 1: Individual Lead Submission

### Request

```
POST /v1/marketdata/ticket-leads
```

**Required headers:**
- `Authorization: {apiKey}`
- `Content-Type: application/json`

### Body

The body varies depending on lead type. Each has a specific structure.

{% conditionaltabs id="tabs-ticket-leads-individual" %}

{% tab label="Ticket Holder" %}

### Ticket Holder - Structure

A **Ticket Holder** is a user who has completed a purchase and owns a valid ticket. This lead type is ideal for identifying potential resale sellers.

#### Required Fields

- `type`: Must be exactly `"TICKET_HOLDER"`
- `externalReferenceEventId`: External event ID
- `showId`: Specific show ID
- `ticketId`: Unique ticket ID
- `buyer`: Object with buyer information (at least one identifier: email, phone, or id)
- `price`: Price paid for the ticket
- `currency`: Currency code (ISO 4217)

#### Complete Example

```json
{
  "type": "TICKET_HOLDER",
  "externalReferenceEventId": "evt_2024_metallica",
  "showId": "show_nyc_20240815",
  "ticketId": "TICKET_abc123def456",
  "buyer": {
    "email": "john.doe@example.com",
    "fullName": "John Doe",
    "id": "user_12345"
  },
  "ticketOptionId": "GA",
  "priceTypeId": "regular",
  "purchaseDate": "2024-12-15T10:30:00Z",
  "price": 99.99,
  "currency": "USD",
  "seating": {
    "section": "A",
    "row": "5",
    "seat": "12"
  },
  "metadata": {
    "section_type": "vip",
    "notes": "Premium seating"
  },
  "tags": ["vip", "early_bird"]
}
```

#### Buyer Fields

The `buyer` object must contain **at least one** of these identifiers:

| Field | Type | Description |
|-------|------|-------------|
| `email` | string | Buyer email (e.g., buyer@example.com) |
| `phone` | string | Buyer phone (e.g., +1234567890) |
| `id` | string | Unique ID in your system (e.g., user_12345, recommended for GDPR/LGPD) |

#### Seating Fields (Optional)

If you have seat information:

```json
"seating": {
  "section": "A",
  "row": "5",
  "seat": "12"
}
```

{% /tab %}

{% tab label="Abandoned Cart" %}

### Abandoned Cart - Structure

An **Abandoned Cart** is a user who started the purchase process but didn't complete the transaction. These users are potential buyers for resale when price or availability changes.

#### Required Fields

- `type`: Must be exactly `"ABANDONED_CART"`
- `externalReferenceEventId`: External event ID
- `showId`: Specific show ID
- `buyer`: Object with user information (at least one identifier)

#### Complete Example

```json
{
  "type": "ABANDONED_CART",
  "externalReferenceEventId": "evt_2024_metallica",
  "showId": "show_nyc_20240815",
  "ticketId": "TICKET_def456ghi789",
  "buyer": {
    "email": "potential@example.com",
    "id": "user_abandoned_1",
    "fullName": "Jane Smith"
  },
  "ticketOptionId": "VIP",
  "priceTypeId": "early_bird",
  "purchaseDate": "2024-12-14T15:45:00Z",
  "price": 149.99,
  "currency": "USD",
  "seating": {
    "section": "B",
    "row": "10"
  },
  "metadata": {
    "last_action": "checkout",
    "items_in_cart": 2,
    "reason_abandoned": "payment_failed"
  },
  "tags": ["abandoned", "recovery_email_sent"]
}
```

#### Note

The `price` and `ticketId` fields are **optional** but recommended. The `purchaseDate` refers to when the cart was abandoned.

{% /tab %}

{% tab label="Virtual Queue" %}

### Virtual Queue - Structure

A **Virtual Queue** is a user who was in the virtual queue to buy tickets but abandoned the process without making a purchase. These users demonstrated real-time interest.

#### Required Fields

- `type`: Must be exactly `"VIRTUAL_QUEUE"`
- `externalReferenceEventId`: External event ID
- `showId`: Specific show ID
- `buyer`: Object with user information (at least one identifier)

#### Complete Example

```json
{
  "type": "VIRTUAL_QUEUE",
  "externalReferenceEventId": "evt_2024_metallica",
  "showId": "show_nyc_20240815",
  "ticketId": "TICKET_ghi789jkl012",
  "buyer": {
    "email": "queue@example.com",
    "id": "user_queue_1",
    "phone": "+1987654321"
  },
  "ticketOptionId": "GA",
  "priceTypeId": "regular",
  "purchaseDate": "2024-12-14T09:15:00Z",
  "price": 99.99,
  "currency": "USD",
  "metadata": {
    "queue_position": 2500,
    "wait_time_minutes": 45,
    "queue_exit_reason": "timeout"
  },
  "tags": ["queue_abandonment", "high_demand"]
}
```

#### Note

The `purchaseDate` in this case refers to when the user abandoned the queue. The `price`, `ticketOptionId`, and `seating` fields are optional.

{% /tab %}

{% tab label="Wishlist" %}

### Wishlist - Structure

A **Wishlist** is a user who explicitly subscribed to receive notifications about ticket availability. This is the highest quality lead: direct opt-in.

#### Required Fields

- `type`: Must be exactly `"WISHLIST"`
- `externalReferenceEventId`: External event ID
- `showId`: Specific show ID
- `buyer`: Object with user information (at least one identifier)

#### Complete Example

```json
{
  "type": "WISHLIST",
  "externalReferenceEventId": "evt_2024_metallica",
  "showId": "show_nyc_20240815",
  "buyer": {
    "email": "wishlist@example.com",
    "id": "user_wishlist_1",
    "fullName": "Michael Brown"
  },
  "ticketOptionId": "VIP",
  "priceTypeId": "vip_early",
  "purchaseDate": "2024-12-10T14:20:00Z",
  "price": 199.99,
  "currency": "USD",
  "metadata": {
    "notification_frequency": "daily",
    "preferred_section": "floor",
    "max_price_willing_to_pay": 250
  }
}
```

#### Note

All fields except `type`, `externalReferenceEventId`, `showId`, and `buyer` are optional. The `purchaseDate` refers to when the item was added to the wishlist.

{% /tab %}

{% /conditionaltabs %}

---

## Endpoint 2: Batch/Bulk Submission

### Request

```
POST /v1/marketdata/ticket-leads/bulk
```

**Required headers:**
- `Authorization: {apiKey}`
- `Content-Type: application/json`

### Body

The body is an **array of leads**. You can mix different types in a single request. Maximum **1000 leads per request**.

```json
[
  {
    "type": "TICKET_HOLDER",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "ticketId": "TICKET_abc123",
    "buyer": {
      "email": "buyer1@example.com",
      "fullName": "John Doe"
    },
    "price": 99.99,
    "currency": "USD"
  },
  {
    "type": "TICKET_HOLDER",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "ticketId": "tkt_091bad9f1d83a",
    "buyer": {
      "id": "usr_9289370133"
    },
    "price": 451.31,
    "currency": "MXN"
  },
  {
    "type": "ABANDONED_CART",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "buyer": {
      "email": "abandoned@example.com"
    },
    "ticketOptionId": "GA"
  },
  {
    "type": "WISHLIST",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "buyer": {
      "email": "wishlist@example.com",
      "id": "user_wishlist_1"
    },
    "ticketOptionId": "VIP"
  }
]
```

### Batch Characteristics

- **Maximum records**: 1000 leads per request
- **Type mixing**: You can include TICKET_HOLDER, ABANDONED_CART, VIRTUAL_QUEUE, and WISHLIST in the same request
- **Individual validation**: Each lead is validated separately
- **Idempotency**: Leads are created or updated based on buyer identifier (email, phone, or id)

---

## API Response

### Successful Response (200 OK)

When a lead is sent correctly, the API returns:

```json
{
  "status": 200,
  "data": true,
  "errors": null
}
```

### Error Handling

If there's an issue, the API returns a descriptive message. Examples:

**Missing required field:**
```json
{
  "status": 400,
  "data": null,
  "errors": {
    "message": "buyer.email or buyer.phone or buyer.id is required"
  }
}
```

**Invalid event ID:**
```json
{
  "status": 404,
  "data": null,
  "errors": {
    "message": "Event not found"
  }
}
```

---

## Common Fields Across All Lead Types

These fields can be included in any lead type:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | Yes | Lead type: TICKET_HOLDER, ABANDONED_CART, VIRTUAL_QUEUE, WISHLIST |
| `externalReferenceEventId` | string | Yes | External event ID |
| `showId` | string | Yes | Specific show ID |
| `buyer` | object | Yes | User information (at least one identifier) |
| `ticketId` | string | Conditional | Required only for TICKET_HOLDER |
| `price` | number | Conditional | Required only for TICKET_HOLDER |
| `currency` | string | No | Currency code (ISO 4217, e.g., USD, MXN, EUR) |
| `ticketOptionId` | string | No | Ticket category ID (GA, VIP, etc.) |
| `priceTypeId` | string | No | Price type ID (early_bird, regular, etc.) |
| `purchaseDate` | string | No | ISO 8601 formatted date (e.g., 2024-12-15T10:30:00Z) |
| `seating` | object | No | Seating information (section, row, seat) |
| `metadata` | object | No | Custom data (free-form JSON) |
| `tags` | array | No | Array of strings for categorization |

---

## Usage Examples

### Case 1: Send Individual Ticket Holder

```bash
curl -X POST "https://api.mentatech.io/v1/marketdata/ticket-leads" \
  -H "Authorization: apiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "TICKET_HOLDER",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "ticketId": "TICKET_abc123def456",
    "buyer": {
      "email": "john.doe@example.com",
      "fullName": "John Doe"
    },
    "price": 99.99,
    "currency": "USD"
  }'
```

### Case 2: Send Individual Abandoned Cart

```bash
curl -X POST "https://api.mentatech.io/v1/marketdata/ticket-leads" \
  -H "Authorization: apiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ABANDONED_CART",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "buyer": {
      "email": "potential@example.com",
      "id": "user_abandoned_1"
    },
    "ticketOptionId": "VIP",
    "price": 149.99,
    "currency": "USD"
  }'
```

### Case 3: Send Mixed Batch (100 leads)

```bash
curl -X POST "https://api.mentatech.io/v1/marketdata/ticket-leads/bulk" \
  -H "Authorization: apiKey" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "type": "TICKET_HOLDER",
      "externalReferenceEventId": "evt_2024_metallica",
      "showId": "show_nyc_20240815",
      "ticketId": "TICKET_001",
      "buyer": { "email": "user1@example.com" },
      "price": 99.99,
      "currency": "USD"
    },
    {
      "type": "ABANDONED_CART",
      "externalReferenceEventId": "evt_2024_metallica",
      "showId": "show_nyc_20240815",
      "buyer": { "email": "user2@example.com" }
    },
    {
      "type": "VIRTUAL_QUEUE",
      "externalReferenceEventId": "evt_2024_metallica",
      "showId": "show_nyc_20240815",
      "buyer": { "id": "user_3" }
    },
    {
      "type": "WISHLIST",
      "externalReferenceEventId": "evt_2024_metallica",
      "showId": "show_nyc_20240815",
      "buyer": { "phone": "+1234567890" },
      "ticketOptionId": "VIP"
    }
  ]'
```

### Case 4: Send Wishlist with Preferences

```bash
curl -X POST "https://api.mentatech.io/v1/marketdata/ticket-leads" \
  -H "Authorization: apiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "WISHLIST",
    "externalReferenceEventId": "evt_2024_metallica",
    "showId": "show_nyc_20240815",
    "buyer": {
      "email": "wishlist@example.com",
      "id": "user_wishlist_1",
      "fullName": "Michael Brown"
    },
    "ticketOptionId": "VIP",
    "metadata": {
      "notification_frequency": "daily",
      "preferred_section": "floor",
      "max_price_willing_to_pay": 250
    }
  }'
```

---

## API Reference

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

{% apiembed endpoint="post-marketdata-leads-batch" show="link" width="auto" /%}

---

## Best Practices

### 1. Buyer Identifiers

Always include **at least one** of these for better tracking:

- **email**: Ideal for direct communications
- **id**: Recommended for GDPR/LGPD compliance (privacy-safe)
- **phone**: Complementary to email

```json
{
  "buyer": {
    "email": "user@example.com",
    "id": "usr_123456",
    "phone": "+1234567890"
  }
}
```

### 2. Metadata for Context

Use `metadata` to add contextual information without affecting the structure:

```json
{
  "metadata": {
    "source": "website_checkout",
    "device": "mobile",
    "referrer": "instagram_ad",
    "utm_campaign": "metallica_tour_2024"
  }
}
```

### 3. Tags for Categorization

Use `tags` to facilitate searches and reporting:

```json
{
  "tags": ["vip_section", "early_bird", "high_value_customer", "recovery_needed"]
}
```

### 4. Batch Submission for Efficiency

When you have multiple leads, always use the bulk endpoint:

```bash
# ✅ Correct: 1000 leads in 1 request
POST /v1/marketdata/ticket-leads/bulk

# ❌ Inefficient: 1000 individual requests
POST /v1/marketdata/ticket-leads (repeated 1000 times)
```

### 5. Idempotency and Upsert

The system uses the buyer identifier to perform upserts:

- If `email` + `externalReferenceEventId` + `showId` exist → **Updates**
- If they don't exist → **Creates** a new record

This means you can send the same lead multiple times without creating duplicates.

---

## Important Notes

- **Authentication required**: All requests must include a valid token in the `Authorization` header
- **externalReferenceEventId**: Use the identifier of the event in your system.
- **showId**: Each lead must specify the show it belongs to (important for multi-date events)
- **Buyer identifier**: At least one (email, phone, or id) is mandatory
- **Maximum bulk**: 1000 leads per request. For more, make multiple requests
- **Automatic upsert**: Leads are automatically updated if they already exist
