{"base_url":"/api/v1","html_url":"/docs","markdown":"# TM Events API Reference\n\nBase URL: `/api/v1`\n\nBrowse this reference in a browser at `/docs`. Raw markdown is at `/docs.md` or `GET /api/v1/docs`.\n\nAll authenticated endpoints require an API key via `?apiKey=\u003ckey\u003e` query parameter or `x-api-key` header. Price keys are seperate.\n\n---\n\n## All Routes\n\n\n| Method | Path                              | Description                           | Scopes                              |\n| ------ | --------------------------------- | ------------------------------------- | ----------------------------------- |\n| `POST` | `/events/`                        | List events with filters              | `events:read`                       |\n| `GET`  | `/events/:id`                     | Get single event                      | `events:read`                       |\n| `GET`  | `/events/third-party/:id`         | Get third-party URLs                  | `events:read`                       |\n| `GET`  | `/events/price/filtered-by-price` | Get events by price range             | `events:read`, `price:read`         |\n| `GET`  | `/events/:id/sectioned-pricing`   | Get per-section pricing               | `events:read`, `price:read`         |\n| `GET`  | `/events/:id/early-pricing`       | Get early host price tiers            | `events:read`, `price:read`         |\n| `GET`  | `/events/:id/early-seats`         | Get configured box-office seat map    | `events:read`, `price:read`         |\n| `GET`  | `/events/:id/early-codes`         | Get early promo codes                 | `events:read`, `code:read`          |\n| `GET`  | `/events/:id/active-price`        | Get active price range                | `events:read`, `active-price:read`  |\n| `POST` | `/events/active-price`            | Get active prices (bulk)              | `events:read`, `active-price:read`  |\n| `GET`  | `/events/cheapest-tickets`        | Get cheapest events                   | `events:read`, `active-price:read`  |\n| `GET`  | `/events/:id/codes`               | Get presale codes                     | `events:read`, `code:read`          |\n| `GET`  | `/events/:id/get-ins`             | Get historical get-in prices          | `events:read`, `get-ins:read`       |\n| `GET`  | `/events/:id/seats`               | Get seat counts (dropped vs pending)  | `events:read`, `stock:read`         |\n| `GET`  | `/events/:id/seats/all`           | Get all seen seats (priced) for event | `events:read`, `stock:read`         |\n| `GET`  | `/events/:id/stock`               | Get full live stock                   | `events:read`, `stock:read`         |\n| `GET`  | `/events/:id/limited-stock`       | Get stock by price break              | `events:read`, `limited-stock:read` |\n| `POST` | `/sales/`                         | List events by sale date              | `events:read`, `sales:read`         |\n| `GET`  | `/sales/event/:eventId`           | Get sales by event                    | `events:read`, `sales:read`         |\n| `GET`  | `/artists/:id/genre`              | Get artist genre                      | `events:read`, `artists:read`       |\n| `GET`  | `/secondaries/compare/ticketmaster/:id` | Compare TM vs secondary get-in   | `secondaries:read`                  |\n| `GET`  | `/secondaries/all/listings`       | Combined marketplace listings         | `secondaries:read`                  |\n| `GET`  | `/secondaries/stubhub/listings/:id` | StubHub listings                    | `secondaries:read`                  |\n| `GET`  | `/secondaries/vividseats/listings/:id` | Vivid Seats listings             | `secondaries:read`                  |\n| `GET`  | `/secondaries/gametime/listings/:id` | Gametime listings                  | `secondaries:read`                  |\n| `GET`  | `/secondaries/seatgeek/listings/:id` | SeatGeek listings                  | `secondaries:read`                  |\n\n\n---\n\n## Events\n\nBase path: `/api/v1/events`\n\nAll event routes pass through logging and rate-limit middleware.\n\n---\n\n### `POST /`\n\nList events with filters.\n\n**Auth:** None (public)\n\n**Request Body:**\n\n```json\n{\n  \"filters\": {\n    \"eventStartDate\": \"2025-06-01\",\n    \"eventEndDate\": \"2025-12-31\",\n    \"status\": \"onsale\",\n    \"sort\": \"date\",\n    \"order\": \"desc\",\n    \"page\": 0,\n    \"limit\": 25,\n    \"onlyTmEvents\": false,\n    \"vividStrict\": false,\n    \"excludePastEvents\": true,\n    \"tmStrict\": false,\n    \"maxInventory\": 0\n  }\n}\n```\n\n\n| Field               | Type                | Description                                      |\n| ------------------- | ------------------- | ------------------------------------------------ |\n| `eventStartDate`    | string (YYYY-MM-DD) | Start of date range (default: today)             |\n| `eventEndDate`      | string (YYYY-MM-DD) | End of date range (default: 1 year from start)   |\n| `status`            | string              | Filter by event status                           |\n| `sort`              | string              | `\"date\"` or `\"status\"`                           |\n| `order`             | string              | `\"asc\"` or `\"desc\"`                              |\n| `page`              | int                 | Page number (0-indexed)                          |\n| `limit`             | int                 | Results per page (min 10)                        |\n| `onlyTmEvents`      | bool                | Only include events with a TM ID                 |\n| `vividStrict`       | bool                | Only include events with a Vivid Seats ID        |\n| `excludePastEvents` | bool                | Exclude events that have already started         |\n| `tmStrict`          | bool                | Only include events with updated seat inventory  |\n| `maxInventory`      | int                 | Max available seats filter (requires `tmStrict`) |\n\n\n**Response (200):**\n\n```json\n{\n  \"data\": {\n    \"events\": [\n      {\n        \"tm_id\": \"abc123\",\n        \"name\": \"Event Name\",\n        \"start_time\": \"2025-07-01T20:00:00Z\",\n        \"end_time\": \"2025-07-01T23:00:00Z\",\n        \"status\": \"onsale\",\n        \"url\": \"https://www.ticketmaster.com/...\",\n        \"image_url\": \"https://...\",\n        \"currency\": \"USD\",\n        \"category\": \"Music\",\n        \"genre\": \"Rock\",\n        \"venue\": {\n          \"name\": \"Madison Square Garden\",\n          \"capacity\": 20000,\n          \"street\": \"4 Pennsylvania Plaza\",\n          \"city\": \"New York\",\n          \"state\": \"NY\",\n          \"country\": \"US\"\n        },\n        \"price\": {\n          \"min_price\": 49.99,\n          \"max_price\": 299.99,\n          \"currency\": \"USD\"\n        },\n        \"sales\": {\n          \"public\": {\n            \"start_date_time\": \"2025-05-01T10:00:00Z\",\n            \"end_date_time\": \"2025-07-01T18:00:00Z\",\n            \"start_tbd\": false\n          },\n          \"presales\": [\n            {\n              \"name\": \"Artist Presale\",\n              \"description\": \"Exclusive artist presale\",\n              \"start_date_time\": \"2025-04-28T10:00:00Z\",\n              \"end_date_time\": \"2025-04-30T22:00:00Z\",\n              \"url\": \"https://...\",\n              \"visible\": true\n            }\n          ]\n        },\n        \"details\": {\n          \"stubhub\": {\n            \"url\": \"https://...\",\n            \"relevent_id\": \"...\",\n            \"low_price\": 55.0,\n            \"high_price\": 500.0,\n            \"total_listings\": 120,\n            \"total_seats\": 350\n          },\n          \"vivid_seats\": { \"...\" : \"...\" },\n          \"seat_geek\": { \"...\" : \"...\" },\n          \"game_time\": { \"...\" : \"...\" },\n          \"automatiq\": { \"...\" : \"...\" }\n        },\n        \"attraction\": {\n          \"name\": \"Artist Name\",\n          \"type\": \"Music\",\n          \"upcoming_events\": 15,\n          \"url\": \"https://...\",\n          \"seo_name\": \"artist-name\",\n          \"league\": \"\"\n        }\n      }\n    ]\n  },\n  \"total\": 1500,\n  \"count\": 25,\n  \"page\": 0,\n  \"total_pages\": 60,\n  \"pages_remaining\": 59,\n  \"limit\": 25\n}\n```\n\n---\n\n### `GET /:id`\n\nGet a single event by TM ID.\n\n**Auth:** `events:read`\n\n**Params:**\n\n- `id` (path) -- Ticketmaster event ID\n- `getSales` (query, optional) -- `\"true\"` to include Vivid/StubHub sales data\n\n**Response (200):**\n\n```json\n{\n  \"event\": { \"...EventData...\" }\n}\n```\n\n**Errors:**\n\n- `400` -- Invalid event ID\n- `404` -- Event not found\n\n---\n\n### `GET /third-party/:id`\n\nGet third-party marketplace URLs for an event.\n\n**Auth:** None\n\n**Response (200):**\n\n```json\n{\n  \"name\": \"Event Name\",\n  \"ticketmaster\": \"https://www.ticketmaster.com/...\",\n  \"vivid\": \"https://www.vividseats.com/...\",\n  \"stubhub\": \"https://www.stubhub.com/...\",\n  \"seatGeek\": \"https://www.seatgeek.com/...\"\n}\n```\n\n---\n\n### `GET /price/filtered-by-price`\n\nGet events filtered by price range.\n\n**Auth:** `price:read`\n\n**Query Params:**\n\n- `minPrice` (required) -- Minimum price\n- `maxPrice` (optional, default: `999999999`) -- Maximum price\n- `countryCode` (optional, default: `\"US\"`) -- Comma-separated country codes\n\n**Response (200):**\n\n```json\n{\n  \"events\": [ \"...EventData[]...\" ],\n  \"total\": 42\n}\n```\n\n---\n\n### `GET /:id/sectioned-pricing`\n\nGet per-section min/max pricing for an event (live from websocket monitor).\n\n**Auth:** `events:read`, `price:read`\n\n**Response (200):**\n\n```json\n{\n  \"ticketMapper\": {\n    \"ORCH1\": {\n      \"section\": \"ORCH1\",\n      \"minPrice\": 89.50,\n      \"maxPrice\": 350.00\n    },\n    \"MEZZ2\": {\n      \"section\": \"MEZZ2\",\n      \"minPrice\": 45.00,\n      \"maxPrice\": 120.00\n    }\n  }\n}\n```\n\n---\n\n### `GET /:id/early-pricing`\n\nGet the host price scale for an event as soon as the venue box office loads it,\noften before the public pricing buffer has anything.\n\n**Auth:** `events:read`, `price:read`\n\n**Query:**\n\n| Param | Default | Description |\n| ----- | ------- | ----------- |\n| `availability` | `true` | Include live seat counts per tier. |\n| `allTicketTypes` | `false` | Include senior/student/group variants; default is base adult only. |\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"150064F581713D8B\",\n  \"currency\": \"USD\",\n  \"minPrice\": 73.75,\n  \"maxPrice\": 133.75,\n  \"totalAvailableSeats\": 842,\n  \"pricing\": [\n    {\n      \"faceValue\": 129.5,\n      \"fees\": 4.25,\n      \"total\": 133.75,\n      \"availableSeats\": 120,\n      \"maximumContiguousSeats\": 8\n    }\n  ]\n}\n```\n\n**Errors:**\n\n- `404` -- Early pricing is unavailable for this event\n\n---\n\n### `GET /:id/early-seats`\n\nGet the configured section, row, and seat ranges joined to their preloaded\nprice codes. This seat map is often available before public onsale and is not\nlive inventory — a configured range can still be held back when the sale opens.\n\n**Auth:** `events:read`, `price:read`\n\n`totalSeats` is the venue summary when present, otherwise the sum of parsed\nranges. `priceMappedSeatCount` is seats that joined to at least one price\ncode; `unpricedSeatCount` is the remainder. Ranges with no matching price\ncode omit `pricing`. All money fields are major currency units.\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"150064F581713D8B\",\n  \"currency\": \"USD\",\n  \"totalSeats\": 1840,\n  \"sectionCount\": 12,\n  \"seatRangeCount\": 86,\n  \"priceMappedSeatCount\": 1620,\n  \"unpricedSeatCount\": 220,\n  \"sections\": [\n    {\n      \"name\": \"101\",\n      \"description\": \"Lower Bowl\",\n      \"type\": \"Standard\",\n      \"generalAdmission\": false,\n      \"seatCount\": 48,\n      \"ranges\": [\n        {\n          \"row\": \"A\",\n          \"firstSeat\": \"1\",\n          \"lastSeat\": \"8\",\n          \"seatCount\": 8,\n          \"seatIncrement\": 1,\n          \"pricing\": [\n            {\n              \"description\": \"Adult\",\n              \"faceValue\": 129.5,\n              \"fees\": 4.25,\n              \"tax\": 0,\n              \"serviceCharge\": 0,\n              \"total\": 133.75\n            }\n          ]\n        },\n        {\n          \"row\": \"B\",\n          \"firstSeat\": \"1\",\n          \"lastSeat\": \"8\",\n          \"seatCount\": 8,\n          \"seatIncrement\": 1\n        }\n      ]\n    }\n  ]\n}\n```\n\nResponses are cached for 2 minutes (`Cache-Control: public, max-age=…`).\n\n**Errors:**\n\n- `400` -- Missing event ID\n- `404` -- Early seats are unavailable for this event\n\n---\n\n### `GET /:id/early-codes`\n\nGet early promo codes for an event.\n\n**Auth:** `events:read`, `code:read`\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"abc123\",\n  \"codes\": [\"PRESALE\"]\n}\n```\n\nAn event with no matching code returns an empty `codes` array.\n\n**Errors:**\n\n- `404` -- Early codes are unavailable for this event\n\n---\n\n### `GET /:id/active-price`\n\nGet the active (real-time) price range for an event.\n\n**Auth:** `events:read`, `active-price:read`\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"abc123\",\n  \"prices\": {\n    \"minPrice\": 29.99,\n    \"maxPrice\": 499.99,\n    \"allInMinPrice\": 45.00,\n    \"allInMaxPrice\": 525.00,\n    \"allInMinPriceFiltered\": 50.00,\n    \"allInMaxPriceFiltered\": 510.00,\n    \"facilityFee\": 5.50,\n    \"updatedAt\": \"2025-06-15T14:30:00Z\"\n  }\n}\n```\n\n---\n\n### `POST /active-price`\n\nGet active prices for multiple events at once.\n\n**Auth:** `active-price:read`\n\n**Request Body:**\n\n```json\n{\n  \"event_ids\": [\"abc123\", \"def456\", \"ghi789\"]\n}\n```\n\n**Response (200):**\n\n```json\n{\n  \"data\": [\n    {\n      \"eventId\": \"abc123\",\n      \"prices\": {\n        \"minPrice\": 29.99,\n        \"maxPrice\": 499.99,\n        \"allInMinPrice\": 45.00,\n        \"allInMaxPrice\": 525.00,\n        \"allInMinPriceFiltered\": 50.00,\n        \"allInMaxPriceFiltered\": 510.00,\n        \"facilityFee\": 5.50,\n        \"updatedAt\": \"2025-06-15T14:30:00Z\"\n      }\n    }\n  ]\n}\n```\n\n---\n\n### `GET /cheapest-tickets`\n\nGet cheapest active-priced events within a date range.\n\n**Auth:** `active-price:read`\n\n**Query Params:**\n\n- `limit` (optional, default: `25`, max: `300`)\n- `startDate` (optional, RFC3339, default: yesterday)\n- `endDate` (optional, RFC3339, default: tomorrow)\n- `maxPrice` (optional) -- Max all-in min price filter\n\n**Response (200):**\n\n```json\n{\n  \"data\": [ \"...ActivePriceResponse[]...\" ]\n}\n```\n\n---\n\n### `GET /:id/codes`\n\nGet presale/offer codes for an event (live from websocket monitor + database).\n\n**Auth:** `events:read`, `code:read`\n\n**Response (200):**\n\n```json\n[\n  {\n    \"ID\": \"...\",\n    \"EventID\": \"abc123\",\n    \"Code\": \"510002\",\n    \"Name\": \"Mastercard presales\"\n  }\n]\n```\n\n---\n\n### `GET /:id/get-ins`\n\nGet historical \"get-in\" prices for an event.\n\n**Auth:** `events:read`, `get-ins:read`\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"abc123\",\n  \"prices\": [\n    {\n      \"price\": 55.00,\n      \"market\": \"primary\",\n      \"currency\": \"USD\",\n      \"scrapedAt\": \"2025-06-10T12:00:00Z\"\n    }\n  ]\n}\n```\n\n---\n\n### `GET /:id/seats`\n\nGet seat counts for an event, split by priced vs unpriced.\n\n**Auth:** `events:read`, `stock:read`\n\n**Response (200):**\n\n```json\n{\n  \"event_id\": \"abc123\",\n  \"total\": 5000,\n  \"seen\": 3200,\n  \"pending\": 1800\n}\n```\n\n---\n\n### `GET /:id/seats/all`\n\nDump every \"seen\" seat for an event (rows where `list_price \u003e 0`). No pagination — returns the full set.\n\n**Auth:** `events:read`, `stock:read`\n\n**Response (200):**\n\n```json\n{\n  \"event_id\": \"abc123\",\n  \"count\": 3200,\n  \"seats\": [\n    {\n      \"Section\": \"111A\",\n      \"Row\": \"29\",\n      \"SeatNumber\": 14,\n      \"Name\": \"POTENT\",\n      \"Description\": \"Artist Presale\",\n      \"Password\": true,\n      \"ListPrice\": 119.5,\n      \"FaceValue\": 115,\n      \"FacilityFees\": 4.5,\n      \"ServiceCharge\": 30.45,\n      \"FirstSeenAt\": \"2025-06-10T12:00:00Z\",\n      \"LastUpdatedAt\": \"2025-06-15T14:30:00Z\"\n    }\n  ]\n}\n```\n\n---\n\n### `GET /:id/stock`\n\nGet full live stock (all available tickets) for an event.\n\n**Auth:** `events:read`, `stock:read`\n\nA numeric `:id` is a SeatGeek event id (SeatGeek-primary). Those return this\nsame shape from SeatGeek box-office inventory (`open` and `mercury` markets)\nand are not looked up as Ticketmaster events. `codes` is then SeatGeek's\nprice types, keyed by price type id, with `code` the price type label. `map`\nis empty. A stored event whose URL is `seatgeek.com`, or that is neither\nTicketmaster nor AXS and has a SeatGeek id, takes the same path. Every other\nevent still comes from the Ticketmaster feed.\n\n**Query Params:**\n\n- `did` (optional, default: `\"default\"`) -- Display ID\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"abc123\",\n  \"availableSeats\": 1500,\n  \"platinumSeats\": 75,\n  \"map\": \"https://mapsapi.tmol.io/maps/geometry/3/event/abc123/image?...\",\n  \"bySection\": {\n    \"ORCH1\": 120,\n    \"MEZZ2\": 85\n  },\n  \"codes\": {\n    \"Mastercard Presale\": {\n      \"code\": \"Mastercard Presale\",\n      \"description\": \"...\",\n      \"quantity\": 50\n    }\n  },\n  \"stock\": [\n    {\n      \"name\": \"Standard Ticket\",\n      \"section\": \"ORCH1\",\n      \"row\": \"A\",\n      \"seat\": \"12\",\n      \"listPrice\": 150.00,\n      \"faceValue\": 125.00,\n      \"facilityFee\": 10.00,\n      \"serviceCharge\": 15.00,\n      \"password\": false\n    }\n  ],\n  \"consecutivePairs\": 25,\n  \"pairs\": [\n    [\n      { \"section\": \"ORCH1\", \"row\": \"A\", \"seat\": \"12\", \"...\" : \"...\" },\n      { \"section\": \"ORCH1\", \"row\": \"A\", \"seat\": \"13\", \"...\" : \"...\" }\n    ]\n  ]\n}\n```\n\n**Errors:**\n\n- `404` -- No stock available\n\n---\n\n### `GET /:id/limited-stock`\n\nGet stock summarized by price break (no individual ticket listing).\n\n**Auth:** `limited-stock:read`\n\n**Query Params:**\n\n- `did` (optional, default: `\"default\"`)\n\n**Response (200):**\n\n```json\n{\n  \"eventId\": \"abc123\",\n  \"availableSeats\": 1500,\n  \"priceBreaks\": [\n    {\n      \"listPrice\": 150.00,\n      \"faceValue\": 125.00,\n      \"facilityFee\": 10.00,\n      \"serviceCharge\": 15.00,\n      \"quantity\": 200\n    },\n    {\n      \"listPrice\": 85.00,\n      \"faceValue\": 70.00,\n      \"facilityFee\": 5.00,\n      \"serviceCharge\": 10.00,\n      \"quantity\": 450\n    }\n  ]\n}\n```\n\n---\n\n## Sales\n\nBase path: `/api/v1/sales`\n\n**Auth (all routes):** `sales:read`\n\n---\n\n### `POST /`\n\nList events by sale date range (presale/public sale start dates).\n\n**Request Body:**\n\n```json\n{\n  \"filters\": {\n    \"eventId\": \"abc123\",\n    \"saleStartDate\": \"2025-06-01\",\n    \"saleEndDate\": \"2025-06-30\",\n    \"status\": \"onsale\",\n    \"sort\": \"date\",\n    \"order\": \"desc\",\n    \"page\": 0,\n    \"limit\": 25\n  }\n}\n```\n\n**Response (200):**\n\n```json\n{\n  \"data\": {\n    \"events\": [ \"...EventData[]...\" ]\n  },\n  \"total\": 100,\n  \"count\": 25,\n  \"page\": 0,\n  \"total_pages\": 4,\n  \"pages_remaining\": 3,\n  \"limit\": 25\n}\n```\n\n---\n\n### `GET /event/:eventId`\n\nGet sales by event ID.\n\n**Response (200):**\n\n```json\n{\n  \"message\": \"Get sales by event\",\n  \"eventId\": \"abc123\"\n}\n```\n\n---\n\n## Artists\n\nBase path: `/api/v1/artists`\n\n**Auth (all routes):** `artists:read`\n\n---\n\n### `GET /:id/genre`\n\nGet genre classification for an artist by legacy ID.\n\n**Response (200):**\n\n```json\n{\n  \"artist_id\": \"K8vZ917...\",\n  \"artist_name\": \"Artist Name\",\n  \"genre\": \"Rock\",\n  \"sub_genre\": \"Alternative\",\n  \"sub_type\": \"Band\",\n  \"segment\": \"Music\",\n  \"url\": \"https://...\"\n}\n```\n\n---\n\n## Secondaries\n\nBase path: `/api/v1/secondaries`\n\n**Auth (all routes):** `secondaries:read`\n\nAll secondaries routes pass through logging and rate-limit middleware.\n\nListings are normalized into a shared shape. Sections are grouped into **zones**\n(`100s`, `200s`, …; sections under 100 become `Floor`; named areas like `GA`\nstay as-is). `getIn` is the cheapest listing price; `highTicket` is the most\nexpensive.\n\nSingle-marketplace listing endpoints populate `getIn`, `highTicket`, and\n`breakdown`. `GET /all/listings` and `GET /compare/ticketmaster/:id` merge\nlistings across sources and do not aggregate those top-level fields.\n\n---\n\n### `GET /compare/ticketmaster/:id`\n\nCompare Ticketmaster dropped-seat (primary) get-in prices per zone against\nStubHub, Vivid Seats, Gametime, and SeatGeek get-in prices for the same event.\n\n`:id` is a Ticketmaster event ID. Linked marketplace IDs are resolved from the\nevent record (`stubhub`, `vividseats`, `gametime`, and `seatgeek` when present).\nA marketplace with no linked ID is skipped.\n\n`percentChange` is the change from the primary get-in to the secondary get-in:\npositive means the secondary market is more expensive (markup); negative means\nit is cheaper than the dropped-seat price.\n\n**Auth:** `secondaries:read`\n\n**Params:**\n\n- `id` (path) -- Ticketmaster event ID\n\n**Response (200):**\n\n```json\n{\n  \"total\": 4200,\n  \"totalListings\": 980,\n  \"getIn\": 0,\n  \"highTicket\": 0,\n  \"eventIds\": {\n    \"ticketmaster\": \"abc123\",\n    \"stubhub\": \"104512345\",\n    \"vividseats\": \"3845123\",\n    \"seatgeek\": \"6123456\",\n    \"gametime\": \"gt_abc123\"\n  },\n  \"comparison\": [\n    {\n      \"zone\": \"100s\",\n      \"primaryGetIn\": 89.50,\n      \"primaryPriceBreaks\": [\n        { \"price\": 89.50, \"seats\": 24 },\n        { \"price\": 125.00, \"seats\": 18 }\n      ],\n      \"marketplaces\": [\n        {\n          \"marketplace\": \"gametime\",\n          \"getIn\": 112.00,\n          \"difference\": 22.50,\n          \"percentChange\": 25.14\n        },\n        {\n          \"marketplace\": \"stubhub\",\n          \"getIn\": 145.00,\n          \"difference\": 55.50,\n          \"percentChange\": 62.01\n        },\n        {\n          \"marketplace\": \"vividseats\",\n          \"getIn\": 138.00,\n          \"difference\": 48.50,\n          \"percentChange\": 54.19\n        }\n      ]\n    }\n  ],\n  \"listings\": [\n    {\n      \"marketplace\": \"stubhub\",\n      \"section\": \"111\",\n      \"row\": \"12\",\n      \"qty\": 2,\n      \"price\": 145.00,\n      \"formattedPrice\": \"$145.00\"\n    },\n    {\n      \"marketplace\": \"ticketmaster\",\n      \"section\": \"111A\",\n      \"row\": \"14\",\n      \"qty\": 1,\n      \"price\": 89.50,\n      \"formattedPrice\": \"$89.50\"\n    }\n  ]\n}\n```\n\nPrimary listings use all-in price (`faceValue + facilityFees + serviceCharge`).\n`primaryPriceBreaks` only count Ticketmaster seats that are currently in stock.\n\n**Errors:**\n\n- `400` -- Missing event ID\n- `500` -- Failed to load the event, dropped seats, or marketplace listings\n\n---\n\n### `GET /all/listings`\n\nFetch listings from multiple marketplaces in one request and return them as a\nsingle combined list.\n\nAt least one of `vividId`, `stubhubId`, `gametimeId`, or `seatgeekId` is\nrequired. Each marketplace is fetched only when its id is provided.\n\n**Auth:** `secondaries:read`\n\n**Query Params:**\n\n- `vividId` (optional) -- Vivid Seats event ID\n- `stubhubId` (optional) -- StubHub event ID\n- `gametimeId` (optional) -- Gametime event ID\n- `seatgeekId` (optional) -- SeatGeek event ID\n- `zoneId` (optional) -- StubHub zone/selection filter (`selection`). Ignored\n  for Vivid Seats, Gametime, and SeatGeek.\n\n**Response (200):**\n\n```json\n{\n  \"total\": 850,\n  \"totalListings\": 210,\n  \"getIn\": 0,\n  \"highTicket\": 0,\n  \"listings\": [\n    {\n      \"marketplace\": \"vividseats\",\n      \"section\": \"111\",\n      \"row\": \"8\",\n      \"qty\": 2,\n      \"price\": 138.00,\n      \"formattedPrice\": \"138.00\"\n    },\n    {\n      \"marketplace\": \"stubhub\",\n      \"section\": \"111\",\n      \"row\": \"12\",\n      \"qty\": 2,\n      \"price\": 145.00,\n      \"formattedPrice\": \"$145.00\"\n    },\n    {\n      \"marketplace\": \"gametime\",\n      \"section\": \"112\",\n      \"row\": \"4\",\n      \"qty\": 3,\n      \"price\": 112.00,\n      \"formattedPrice\": \"$112.00\"\n    }\n  ]\n}\n```\n\nA marketplace that fails to fetch is omitted from the result (the others still\nreturn). `breakdown` is not populated on this endpoint.\n\n**Errors:**\n\n- `400` -- No marketplace event ID was provided\n\n---\n\n### `GET /stubhub/listings/:id`\n\nGet StubHub listings for an event, with zone-level breakdown.\n\n**Auth:** `secondaries:read`\n\n**Params:**\n\n- `id` (path) -- StubHub event ID\n- `zoneId` (query, optional) -- Zone/selection filter (`selection`)\n\n**Response (200):**\n\n```json\n{\n  \"total\": 420,\n  \"totalListings\": 95,\n  \"getIn\": 89.00,\n  \"highTicket\": 650.00,\n  \"breakdown\": {\n    \"stubhub\": {\n      \"count\": 420,\n      \"getIn\": 89.00,\n      \"highTicket\": 650.00,\n      \"zones\": {\n        \"100s\": {\n          \"seats\": 180,\n          \"listings\": 40,\n          \"getIn\": 145.00,\n          \"highTicket\": 425.00\n        },\n        \"200s\": {\n          \"seats\": 240,\n          \"listings\": 55,\n          \"getIn\": 89.00,\n          \"highTicket\": 650.00\n        }\n      }\n    }\n  },\n  \"listings\": [\n    {\n      \"marketplace\": \"stubhub\",\n      \"section\": \"111\",\n      \"row\": \"12\",\n      \"qty\": 2,\n      \"price\": 145.00,\n      \"formattedPrice\": \"$145.00\"\n    }\n  ]\n}\n```\n\n**Errors:**\n\n- `400` -- Missing event ID\n- `500` -- Failed to get listings\n\n---\n\n### `GET /vividseats/listings/:id`\n\nGet Vivid Seats listings for an event, with zone-level breakdown.\n\nPrices are all-in (`aip`).\n\n**Auth:** `secondaries:read`\n\n**Params:**\n\n- `id` (path) -- Vivid Seats event ID\n\n**Response (200):**\n\n```json\n{\n  \"total\": 310,\n  \"totalListings\": 72,\n  \"getIn\": 92.00,\n  \"highTicket\": 480.00,\n  \"breakdown\": {\n    \"vividseats\": {\n      \"count\": 310,\n      \"getIn\": 92.00,\n      \"highTicket\": 480.00,\n      \"zones\": {\n        \"100s\": {\n          \"seats\": 140,\n          \"listings\": 30,\n          \"getIn\": 138.00,\n          \"highTicket\": 380.00\n        }\n      }\n    }\n  },\n  \"listings\": [\n    {\n      \"marketplace\": \"vividseats\",\n      \"section\": \"111\",\n      \"row\": \"8\",\n      \"qty\": 2,\n      \"price\": 138.00,\n      \"formattedPrice\": \"138.00\"\n    }\n  ]\n}\n```\n\n**Errors:**\n\n- `400` -- Missing event ID\n- `500` -- Failed to get listings\n\n---\n\n### `GET /gametime/listings/:id`\n\nGet Gametime listings for an event, with zone-level breakdown.\n\nPrices are all-in totals (cents converted to dollars).\n\n**Auth:** `secondaries:read`\n\n**Params:**\n\n- `id` (path) -- Gametime event ID\n\n**Response (200):**\n\n```json\n{\n  \"total\": 120,\n  \"totalListings\": 43,\n  \"getIn\": 78.00,\n  \"highTicket\": 320.00,\n  \"breakdown\": {\n    \"gametime\": {\n      \"count\": 120,\n      \"getIn\": 78.00,\n      \"highTicket\": 320.00,\n      \"zones\": {\n        \"Floor\": {\n          \"seats\": 48,\n          \"listings\": 16,\n          \"getIn\": 210.00,\n          \"highTicket\": 320.00\n        },\n        \"100s\": {\n          \"seats\": 72,\n          \"listings\": 27,\n          \"getIn\": 78.00,\n          \"highTicket\": 195.00\n        }\n      }\n    }\n  },\n  \"listings\": [\n    {\n      \"marketplace\": \"gametime\",\n      \"section\": \"112\",\n      \"row\": \"4\",\n      \"qty\": 3,\n      \"price\": 112.00,\n      \"formattedPrice\": \"$112.00\"\n    }\n  ]\n}\n```\n\n**Errors:**\n\n- `400` -- Missing event ID\n- `500` -- Failed to get listings\n\n---\n\n### `GET /seatgeek/listings/:id`\n\nGet SeatGeek listings for an event, with zone-level breakdown.\n\n`:id` is a SeatGeek numeric event ID. Every seller channel is included (box\noffice and resale). `price` is the all-in price per ticket and `qty` is the\nlisting quantity.\n\nSeatGeek sits behind DataDome; challenges are solved transparently. A cold\ncall takes a couple of seconds, and later calls for the same event reuse the\nsession.\n\n**Auth:** `secondaries:read`\n\n**Params:**\n\n- `id` (path) -- SeatGeek event ID\n\n**Response (200):**\n\n```json\n{\n  \"total\": 3961,\n  \"totalListings\": 1064,\n  \"getIn\": 89.00,\n  \"highTicket\": 1494.72,\n  \"breakdown\": {\n    \"seatgeek\": {\n      \"count\": 3961,\n      \"getIn\": 89.00,\n      \"highTicket\": 1494.72,\n      \"zones\": {\n        \"100s\": {\n          \"seats\": 2140,\n          \"listings\": 612,\n          \"getIn\": 89.00,\n          \"highTicket\": 1494.72\n        }\n      }\n    }\n  },\n  \"listings\": [\n    {\n      \"marketplace\": \"seatgeek\",\n      \"section\": \"105\",\n      \"row\": \"1\",\n      \"qty\": 2,\n      \"price\": 1494.72,\n      \"formattedPrice\": \"$1494.72\"\n    }\n  ]\n}\n```\n\n**Errors:**\n\n- `400` -- Missing event ID\n- `404` -- Event not found\n- `500` -- Failed to get listings\n\n---\n\n## Available Auth Scopes\n\n\n| Scope                | Description                       | Includes                    |\n| -------------------- | --------------------------------- | --------------------------- |\n| `events:read`        | Read event data                   | —                           |\n| `price:read`         | Read pricing data                 | `events:read`               |\n| `active-price:read`  | Read active/real-time prices      | `events:read`               |\n| `stock:read`         | Read live stock data              | `events:read`               |\n| `limited-stock:read` | Read limited stock (price breaks) | `events:read`, `stock:read` |\n| `code:read`          | Read presale codes                | `events:read`               |\n| `get-ins:read`       | Read get-in prices                | `events:read`               |\n| `sales:read`         | Read sales data                   | `events:read`               |\n| `artists:read`       | Read artist data                  | `events:read`               |\n| `secondaries:read`   | Read secondary-market listings    | `events:read`               |\n\n\n\u003e The `Includes` column lists scopes automatically granted when this scope is subscribed. For example, subscribing to `active-price:read` also grants `events:read` and `price:read` at no additional cost — you only pay the `active-price:read` tier price.\n\n---\n\n## Scope Pricing\n\nEach scope is priced individually based on the customer's monthly request volume for endpoints covered by that scope. Prices below are in USD per month and represent the **flat monthly cost** for the included request quota in that tier. Subscribing to any scope automatically grants the bundled scopes listed in the [Available Auth Scopes](#available-auth-scopes) table (e.g. every paid scope includes `events:read`).\n\n\u003e Tiers are billed monthly. A customer subscribes to one tier per scope. Combined / bundled pricing is negotiated separately for Enterprise.\n\n\n| Scope                | Tier 1 — up to 1K req/mo | Tier 2 — up to 10K req/mo | Tier 3 — up to 50K req/mo | Enterprise (100K+ req/mo) |\n| -------------------- | ------------------------ | ------------------------- | ------------------------- | ------------------------- |\n| `events:read`        | $200                     | $500                      | $1,000                    | Contact sales             |\n| `price:read`         | $TBD                     | $TBD                      | $TBD                      | Contact sales             |\n| `active-price:read`  | $300                     | $750                      | $1,250                    | Contact sales             |\n| `stock:read`         | $400                     | $900                      | $2,000                    | Contact sales             |\n| `limited-stock:read` | $450                     | $1000                     | $2,200                    | Contact sales             |\n| `code:read`          | $300                     | $750                      | $1,250                    | Contact sales             |\n| `get-ins:read`       | $300                     | $750                      | $1,250                    | Contact sales             |\n| `sales:read`         | $300                     | $750                      | $1,250                    | Contact sales             |\n| `artists:read`       | $220                     | $525                      | $1,050                    | Contact sales             |\n| `secondaries:read`   | $TBD                     | $TBD                      | $TBD                      | Contact sales             |\n\n\n### Billing Notes\n\n- A \"request\" is any successful (`2xx`) or client-error (`4xx`, excluding `429`) response on an endpoint that requires the given scope.\n- `429` (rate-limited) and `5xx` responses are not billed.\n- If an endpoint requires multiple scopes (e.g. `/events/:id/sectioned-pricing` requires `events:read` + `price:read`), the request counts against **each** subscribed scope's quota.\n- Unused quota does not roll over month to month.\n- Exceeding a tier's request quota requires upgrading to the next tier for the following billing period.\n\n---\n\n## Common Error Responses\n\nAll error responses follow this format:\n\n```json\n{\n  \"error\": \"Description of the error\"\n}\n```\n\n\n| Status | Meaning                                   |\n| ------ | ----------------------------------------- |\n| `400`  | Bad request / missing required parameters |\n| `401`  | Missing or invalid API key                |\n| `403`  | Insufficient permissions (wrong scopes)   |\n| `404`  | Resource not found                        |\n| `429`  | Rate limit exceeded                       |\n| `500`  | Internal server error                     |\n\n\n### Rate Limit Error (429):\n\n```json\n{\n  \"error\": \"Rate limit exceeded\",\n  \"retry_after\": 1200.5,\n  \"reset_time\": \"2025-06-15T15:30:00Z\",\n  \"rate_limit\": {\n    \"requests_per_window\": 100,\n    \"window_duration_seconds\": 3600\n  }\n}\n```\n\nRate limit headers are included on all authenticated responses:\n\n- `X-RateLimit-Limit` -- Max requests per window\n- `X-RateLimit-Remaining` -- Remaining requests\n- `X-RateLimit-Reset` -- Unix timestamp when window resets\n\n","markdown_url":"/docs.md","title":"TM Events API Reference"}