Tickets.dev
Live ticket listings, all-in prices and seat maps from Ticketmaster, StubHub, SeatGeek, Vivid Seats, TickPick, Gametime and more. Find events, capture one event on one marketplace per call, and compare prices across marketplaces.
Hosted MCP Server
npx add-mcp 'https://api.tickets.dev/mcp'Installs into Claude Code, Codex, Cursor and more
Documentation
API reference
Looking for a marketplace API? Ticketmaster API, StubHub API, SeatGeek API, TickPick API, Vivid Seats API, Gametime API, Viagogo API, GoTickets API, Paciolan API, ATG Tickets API, ProVenue API, GoFevo API, Spotlight.Vegas API, Vegas.com API, Cirque du Soleil API, Broadway Direct API, Telecharge API.
Tickets.dev is a real-time ticket scraping API for retrieving live ticket inventory, pricing, fees, sections, rows, quantities, and seat maps from Ticketmaster, StubHub, SeatGeek, TickPick, Vivid Seats, Gametime, Viagogo, GoTickets, Paciolan, ATG Tickets, ProVenue, GoFevo, Spotlight.Vegas, Vegas.com, and Cirque du Soleil.
Introduction
The Tickets.dev API scrapes live marketplace inventory on demand. There is no crawl to schedule and no cache to go stale: each call opens the event, reads its current listings and prices, and returns the result to you. Ask for the seat maps and it renders those too.
Learn the product concepts in the ticket scraping API, ticket inventory API, ticket price API, seat map API, and ticket events API guides. For complete builds with working code, see how to track ticket prices across marketplaces, compare ticket prices across marketplaces and build price and inventory alerts.
All endpoints live under a single base URL and speak JSON.
https://api.tickets.dev/v1
The same endpoints are described in an OpenAPI 3.1 spec at tickets.dev/openapi.json. Import it into Postman or Insomnia, or generate a client from it.
Same schema, every source. A Ticketmaster capture and a Vivid Seats capture return the identical snapshot object, so you never branch on the marketplace.
Authentication
Every request must carry your API key. Send it in the x-api-key header. Create a key from the account page.
curl -G https://api.tickets.dev/v1/capture/ticketmaster \
--data-urlencode "url=$EVENT_URL" \
-H "x-api-key: $TICKETS_DEV_KEY"
An apiKey query parameter is accepted as well, for callers that can't set a header.
Keep your key server-side. It carries your full quota, so never embed it in client-side code or commit it to a repo. Rotate a key immediately if it leaks. The public sandbox key below cannot spend credits.
Sandbox
There is no separate sandbox host. Same base URL, same paths, same query parameters, same snapshot shape. One public key returns fixtures instead of a live capture.
tk_test_sandbox
Build against that key. Cut over by swapping it for your org's tk_live_… key. Nothing else in the request should have to change: not the URL, not the query, not the parser.
curl -G https://api.tickets.dev/v1/capture/ticketmaster \
--data-urlencode "url=https://www.ticketmaster.com/event/example" \
-H "x-api-key: tk_test_sandbox"
Validation still runs, so a bad request fails the same way it would in production. Responses carry the header Tickets-Sandbox: true. Streaming captures send the same progress events, then the snapshot.
Start in the playground. Sandbox mode uses this key against the real API. Copy the snippet, then replace the key with yours when you go live.
Quickstart
Point the API at any supported event URL. The request runs the capture and returns the whole event: every listing on it, with prices and fees, in one response.
curl -G https://api.tickets.dev/v1/capture/ticketmaster \
--data-urlencode "url=https://www.ticketmaster.com/event/XXXXXXXX" \
-H "x-api-key: $TICKETS_DEV_KEY"
Endpoints
Pass an event URL and every marketplace returns the identical snapshot object. The marketplace is optional: it comes from the URL's host unless you name it with source= or in the path.
| Method | Path | Query | Returns |
|---|---|---|---|
| GET | /v1/capture | ?url=&source=&includeVenueMaps= | Capture one event: every listing on it, in one response. A live key spends one credit; tk_test_sandbox returns a fixture and is never billed. Costs one capture with a live key. |
| GET | /v1/capture/{source} | ?url=&includeVenueMaps= | The same capture with the marketplace in the path, e.g. /v1/capture/ticketmaster. Costs one capture with a live key. |
| GET | /v1/capture/sources | - | The marketplaces you can capture, and the hosts that route to each. Never billable. |
| GET | /v1/health | - | Service status. No key required. |
| GET | /v1/events | ?query=&source=&from=&to=&eventId=&prefix=&page=&pageSize= | Ticket event discovery and matching: search the catalog by name, performer, venue, date, or marketplace URL. Returns one unified event with every matched marketplace ID and URL. Never billed. |
Parameters
| Name | Type | Description |
|---|---|---|
url | string, required | The event page URL from a supported marketplace. |
source | string, optional | Which marketplace to capture from, e.g. ticketmaster. The URL's host already says, so this only adds a check: a URL from any other marketplace returns marketplace_mismatch. See /v1/capture/sources for the values. |
includeVenueMaps | boolean, optional | Render and host the seat maps and fill venueLayout. Off by default, since the maps add time to the capture. Pass true to turn them on. |
Ticket events
/v1/events is the free ticket event discovery and matching API: event name, venue, date, performers, and a sources array of marketplace ids and URLs. Search by name, or pass a marketplace URL to resolve one unified event. It never returns prices, listing counts, or ticket counts. Those stay on capture. Every parameter, response field and error is in the Events API reference; what the catalog is for is on the ticket events API page.
One parameter does the searching. ?query= takes a name, a venue or performer, a slug, or any marketplace URL, with or without a scheme, and works out which it is. An event page returns that event; a venue or performer page returns the upcoming dates. Narrow with ?from= / ?to= and ?source=. Native event ids use ?source=ticketmaster&eventId=; ?eventId= also takes the catalog id. To capture listings and prices, take a sources[].url from the response and pass it to /v1/capture?url=.
The catalog is mapped from Ticketmaster, StubHub, SeatGeek, TickPick, Vivid Seats, Gametime, Viagogo, GoTickets, Paciolan, Cirque du Soleil, Broadway Direct, and Telecharge today, with ATG Tickets, ProVenue, GoFevo, Spotlight.Vegas, and Vegas.com rolling out next. Until one lands, /v1/events answers source_not_indexed for it.
| Name | Type | Description |
|---|---|---|
query | string, optional | The one search input. Free text matches event name, venue, city and performers. A hyphenated slug also matches venue and performer url names. A marketplace URL is resolved directly: an event page returns that event, a venue or performer page returns its dates. |
url | string, optional | Alias for query when the value is a URL. Kept so an event link can be passed under an obvious name. |
eventId | string, optional | Native marketplace event id (with source=) or a catalog id. |
source | string, optional | Restrict to events listed on this marketplace, and scope native ids to it. Each event still returns every marketplace carrying it: this filters which events come back, not which links each one shows. |
from | string, optional | Inclusive UTC start bound, ISO-8601. Searches exclude events that have already started unless you pass this; set it to a past date to include them. |
to | string, optional | Exclusive UTC start bound, ISO-8601. |
page | integer, optional | 1-based page number. Defaults to 1, capped at 200. |
pageSize | integer, optional | Events per page. Defaults to 20, capped at 100. |
Responses carry page, pageSize, total, numberOfPages and hasMore above the events array.
Searches return upcoming events. Ones that have already started are left out unless from says otherwise; events with no start time published are always included, since there is nothing to compare. Exact lookups by eventId or by URL are never filtered by date.
Catalog reads require a key and are never billed.
curl -G https://api.tickets.dev/v1/events \
--data-urlencode "query=eagles sphere" \
--data-urlencode "from=2026-12-01" \
-H "x-api-key: $TICKETS_DEV_KEY"
{
"page": 1,
"pageSize": 20,
"total": 1,
"numberOfPages": 1,
"hasMore": false,
"events": [
{
"id": "01M0FVJHZRFPS6Y3XM5M0BQ1RH",
"name": "The Eagles",
"eventDateLocal": "2026-12-11T20:30:00-08:00",
"eventDateUtc": "2026-12-12T04:30:00.000Z",
"venue": {
"name": "Sphere at The Venetian Resort",
"city": "Las Vegas",
"state": "NV",
"country": "US",
"timezone": "America/Los_Angeles"
},
"performers": [{ "performerId": "44705", "name": "The Eagles", "master": true }],
"sources": [
{
"marketplace": "ticketmaster",
"eventId": "17006483D6FAFC60",
"url": "https://www.ticketmaster.com/eagles-live-at-sphere-las-vegas-nevada-12-11-2026/event/17006483D6FAFC60"
},
{
"marketplace": "vividseats",
"eventId": "7256971",
"url": "https://www.vividseats.com/the-eagles-tickets-las-vegas-sphere-at-the-venetian-resort-12-11-2026--concerts-adult-contemporary/production/7256971"
},
{
"marketplace": "stubhub",
"eventId": "161551904",
"url": "https://www.stubhub.com/the-eagles-las-vegas-tickets-12-11-2026/event/161551904"
},
{
"marketplace": "gotickets",
"eventId": "1794730",
"url": "https://gotickets.com/tickets/1794730/the-eagles-tickets/msg-sphere-las-vegas-nv-12-11-2026"
}
],
"updatedAt": "2026-08-25T09:14:02.418Z"
}
]
}
Take any sources[].url from the response and pass it to /v1/capture?url= to get that marketplace's live listings and prices.
The snapshot object
Every capture returns one snapshot: the full listing payload for one event. It carries the event metadata, the currency, the derived stats, the flat list of listings, URLs to the rendered seat maps, and the venue layout.
| Field | Type | Description |
|---|---|---|
source | string | Marketplace the capture came from, e.g. ticketmaster. |
eventId | string | The marketplace's own id for the event. |
eventName | string | Event title. |
performers | Performer[] | Acts or teams on the bill, each with performerId, name, and master. |
venueId | string | The marketplace's own venue id. |
venueName | string | Venue name. |
venueAddress | string | Street address of the venue. |
venueCity | string | Venue city. |
venueState | string | Venue state or province. |
venueTimezone | string | IANA zone of the venue, e.g. America/Chicago. Empty when the marketplace doesn't publish one. |
eventDateLocal | string | Event date/time in venue-local ISO 8601. |
eventDateUtc | string | The same moment in ISO 8601 UTC. |
sourceUrl | string | The event page the capture read. |
capturedAt | string | When the capture ran, ISO 8601 UTC. |
currency | string | ISO currency code for every price, e.g. USD. |
note | string | The marketplace's own buyer notice for this event. An event with nothing to sell (sold out, canceled, or not yet on sale) is a normal 200 with an empty listings array and the reason here. |
sectionLevelUrl | string | Section-level overview SVG. Empty unless the request passed includeVenueMaps=true. See Seat maps. |
seatLevelUrl | string | Zoomed seat-level SVG. Same includeVenueMaps opt-in as above. |
stats | Stats | Whole-event pricing we derive from listings (see below). |
listings | Listing[] | Every available listing (see below). |
venueLayout | VenueLayout | The venue map as data: sections, rows and seats. Same includeVenueMaps opt-in as the maps. See The venueLayout object. |
{
"source": "ticketmaster",
"eventId": "17006483D6FAFC60",
"eventName": "Eagles Live at Sphere",
"venueId": "189524",
"venueName": "Sphere",
"venueCity": "Las Vegas",
"venueState": "NV",
"venueTimezone": "America/Los_Angeles",
"eventDateLocal": "2026-12-11T20:30:00-08:00",
"eventDateUtc": "2026-12-12T04:30:00+00:00",
"currency": "USD",
"sectionLevelUrl": "https://storage.tickets.dev/…/section.svg",
"seatLevelUrl": "https://storage.tickets.dev/…/seats.svg",
"stats": {
"listingCount": 136,
"ticketCount": 1037,
"getInPrice": 303.08,
"medianPrice": 710.95,
"avgPrice": 746.14,
"maxPrice": 2309.85
},
"listings": [{
"listingId": "",
"inventoryType": "primary",
"section": "208",
"row": "9",
"quantity": 3,
"ticketPrice": 1157.5,
"fee": 208.35,
"totalPrice": 1365.85,
"sellableQuantities": "1,2,3"
}],
"venueLayout": {
"level": "seat",
"capacity": 16390,
"sections": [{
"section": "101",
"group": "",
"ga": false,
"capacity": 522,
"rows": [{ "row": "34", "capacity": 21, "seats": "1,2,3,…,19,20,21" }]
}]
}
}
The stats object
stats is worked out from the listings. Every figure is per ticket and all-in, like totalPrice, and counted per listing: a ten-seat listing counts once. A capture with no listings reports zeroes.
| Field | Type | Description |
|---|---|---|
listingCount | number | How many listings the capture returned. |
ticketCount | number | Total seats across every listing: how deep the inventory is. |
getInPrice | number | Cheapest all-in price per ticket: the get-in price. |
medianPrice | number | Median all-in price per ticket, across listings. |
avgPrice | number | Average all-in price per ticket, across listings. |
maxPrice | number | Highest all-in price per ticket. |
The listing object
Each entry in listings is one group of same-price seats. Every field below comes back from every marketplace.
| Field | Type | Description |
|---|---|---|
listingId | string | Stable id for the listing: the marketplace's own, so compare it within one marketplace. Empty where the marketplace publishes none. |
inventoryType | string | e.g. primary, resale, verified. |
section | string | Section name or number as the marketplace spells it, with a leading Section word removed, so "Section 101" reads 101 everywhere. The same string as the maps' data-section and venueLayout. Case is the marketplace's own, so casefold when joining across marketplaces. |
row | string | Row label. |
quantity | number | Seats available in this listing. |
ticketPrice | number | Face price per ticket, before fees. |
fee | number | Per-ticket fees. |
totalPrice | number | All-in price per ticket, excluding sales tax. Normalized to the same meaning on every marketplace. |
ticketType | string | How the ticket is delivered, e.g. Mobile Transfer. |
sellableQuantities | string | Comma-separated quantities you can actually buy, e.g. 2,4. |
group | string | The marketplace's own seating tier, e.g. Upper. |
seats | string | Comma-separated seat numbers, when exposed by the source. |
listingNotes | string | Seller notes, e.g. Aisle seat. |
dealScore | string | The marketplace's own value-for-money score, as it shows it. Empty where the source doesn't publish one, and not comparable between marketplaces. |
Seat maps
Pass includeVenueMaps=true and the capture renders two SVGs and hosts them for you:
sectionLevelUrl, the overview: the venue outline, the stage, and one shape per section.seatLevelUrl, the zoomed detail: rows or seats, as fine as the venue's map goes.
The two share a viewBox. The seat file is one group in the section map's coordinates, so append it to the same <svg> when someone zooms in. Sections are tens of kilobytes and seats hundreds, so fetch it only on zoom.
Every region carries data-section, and data-row where the map has rows, spelled the way listings[].section spells it, so a listing binds to its shape by name.
The same parameter fills venueLayout: the sections, rows and seats behind those shapes as data.
Without the parameter both fields come back as empty strings. The fields are always present, so a client never has to branch on their existence. seatLevelUrl is also empty where the marketplace publishes only a section level map.
curl -G https://api.tickets.dev/v1/capture/ticketmaster \
--data-urlencode "url=$EVENT_URL" \
--data-urlencode "includeVenueMaps=true" \
-H "x-api-key: $TICKETS_DEV_KEY"
The venueLayout object
venueLayout is the venue map as data: its sections, the rows in each and the seats in each row. It is read from the same map as the seat maps, for this event's setup of the venue. Pass includeVenueMaps=true to get it; without it the field is { "level": "none", "sections": [] }.
Names match. Sections, rows and seats are spelled the same in venueLayout, in listings and in the maps' data-section, data-row and data-seat.
Seats are in order across the row. A row numbered odd on one side of the aisle and even on the other reads 5,3,1,2,4,6, so neighbours sit next to each other in the string.
level is how deep the map goes. Capacities come at seat level, counted from the seats.
| Field | Type | Description |
|---|---|---|
level | string | How deep the map goes: seat, row, section or none. |
capacity | number, optional | Seats in the venue. Only at seat level. |
sections | Section[] | In the map's order. |
Section
| Field | Type | Description |
|---|---|---|
section | string | Matches listings[].section and data-section. |
group | string | The map's zone for the section, e.g. Lower Bowl. Empty if the map has none. |
ga | boolean | General admission: no rows or seats. |
capacity | number, optional | Seats in the section. Only at seat level. |
rows | Row[] | In the map's order. Empty for GA or when the map stops at sections. |
Row
| Field | Type | Description |
|---|---|---|
row | string | Matches listings[].row and data-row. |
capacity | number, optional | Seats in the row. Only at seat level. |
seats | string | Every seat in the row on the map, comma-joined in order across the row. Matches listings[].seats and data-seat. Empty when the map stops at rows. |
{
"level": "seat",
"capacity": 16390,
"sections": [
{
"section": "101",
"group": "",
"ga": false,
"capacity": 522,
"rows": [
{
"row": "33",
"capacity": 21,
"seats": "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21"
},
{
"row": "36",
"capacity": 15,
"seats": "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"
}
]
}
]
}
Marketplaces
Every marketplace returns the same snapshot. Pass an event URL from one of its domains and the marketplace is worked out for you. The paths below are the explicit form, and the last segment of each is also the value for source=:
| Marketplace | Path | Event URL domains |
|---|---|---|
| Ticketmaster API | /v1/capture/ticketmaster | ticketmaster.com, livenation.com, universe.com, ticketweb.uk |
| StubHub API | /v1/capture/stubhub | stubhub.com |
| SeatGeek API | /v1/capture/seatgeek | seatgeek.com |
| TickPick API | /v1/capture/tickpick | tickpick.com |
| Vivid Seats API | /v1/capture/vividseats | vividseats.com |
| Gametime API | /v1/capture/gametime | gametime.co |
| Viagogo API | /v1/capture/viagogo | viagogo.com |
| GoTickets API | /v1/capture/gotickets | gotickets.com |
| Paciolan API | /v1/capture/paciolan | evenue.net |
| ATG Tickets API | /v1/capture/atg | atgtickets.com, us.atgtickets.com |
| ProVenue API | /v1/capture/provenue | mlb.tickets.com, mpv.tickets.com |
| GoFevo API | /v1/capture/gofevo | gofevo.com |
| Spotlight.Vegas API | /v1/capture/spotlight | spotlight.vegas |
| Vegas.com API | /v1/capture/vegascom | vegas.com |
| Cirque du Soleil API | /v1/capture/cirquedusoleil | tickets.cirquedusoleil.com |
| Broadway Direct API | /v1/capture/broadwaydirect | tickets.broadwaydirect.com |
| Telecharge API | /v1/capture/telecharge | www.telecharge.com, tickets.telecharge.com |
Country domains and subdomains work too. Each marketplace is matched on its brand name, so viagogo.de, stubhub.co.uk, ticketmaster.ca and m.ticketmaster.com are all accepted.
A URL from any other host is refused before a capture runs, so it costs nothing: marketplace_mismatch when you named a marketplace, marketplace_required when you didn't. A URL from a different marketplace than the one you named is also marketplace_mismatch.
Errors
Every error carries a stable code and the request_id that also comes back in the x-request-id header. Branch on the code, not the status: several distinct failures share a status, and the code is what tells you whether retrying is worth it.
{
"error": {
"code": "marketplace_mismatch",
"message": "Requested source \"stubhub\" but the URL is a ticketmaster event.",
"outcome": "rejected",
"retryable": false,
"request_id": "6068316c-29d3-447f-b42c-b46f80debd0d"
}
}
outcome and retryable say what to do with any error, including codes added after you integrate.
| outcome | What it means | What to do |
|---|---|---|
success | A capture ran and returned an event. There is no error envelope: this is the 200. | Use the snapshot. This is the only outcome that spends a capture. |
not_found | The capture ran, and the marketplace has no event at that URL. | Fix the URL. Retrying returns the same answer more slowly. |
failure | The capture could not complete. Ours, not yours. | Retry. Back off if it persists, then tell us the request_id. |
rejected | The request never became a capture: the key, the URL, the plan, or capacity. | Fix the request or the account. Only rate_limited is worth waiting out. |
On /capture/stream the response is committed as 200 before the capture starts, so a failure arrives as an error event carrying these same fields rather than as an HTTP status. Read the event, not the status.
| Status | Code | Meaning |
|---|---|---|
400 | missing_url | No url was given. |
400 | invalid_url | url is not a valid http(s) URL. |
400 | marketplace_required | The URL's host is not one of any marketplace's. |
400 | marketplace_mismatch | The source you named and the URL disagree. |
401 | missing_key | No API key was sent. |
401 | invalid_key | The key is unknown or revoked. |
402 | no_plan | No captures remaining. Choose a plan to continue. |
402 | subscription_inactive | The subscription lapsed. Update the payment method. |
404 | unknown_marketplace | No such marketplace. See /v1/capture/sources. |
404 | event_not_found | The marketplace has no event at that URL. Check the URL: retrying returns the same answer. |
429 | quota_exceeded | No captures left on the balance. |
429 | rate_limited | Too many captures in flight, or capacity is saturated. Honour Retry-After. |
502 | capture_failed | The capture could not complete. |
503 | capture_unavailable | Our side is down, not your rate. Safe to retry. |
504 | capture_timeout | The capture did not finish in time. Safe to retry. |
Only success counts against your quota. Failures, rejections and event_not_found are never billed, including the case where a marketplace serves a page for a URL with no event on it, which comes back as 404 event_not_found rather than an empty capture.
Rate limits
Each plan adds captures each invoice and sets a ceiling on how many captures can run at once. Spending them returns 429 quota_exceeded; whatever is left stays on your balance. See the pricing table for the limits on every tier.
A 429 rate_limited means slow down for a moment, not that you are out of quota: either too many of your captures are already running, or capture capacity is momentarily full. It carries a Retry-After header and is never billed. Honour the header and retry. The free ticket events catalog has its own daily limits per organization.
MCP server
Connect Tickets.dev up to Claude, ChatGPT or Cursor and the agent can look up events, pull listings and compare prices for you. It talks to the API over the Model Context Protocol (MCP). The server lives at https://api.tickets.dev/mcp and uses Streamable HTTP.
Add that URL to your client and sign in. Claude Code, Cursor, Claude and ChatGPT (as a custom connector) send you to Tickets.dev to approve the connection, and that creates an API key just for that app. To cut it off later, disconnect it in your account settings. Scripts, and clients that can't sign in, can send your key in an Authorization: Bearer header instead.
claude mcp add --transport http tickets-dev https://api.tickets.dev/mcp
# then run /mcp, pick tickets-dev and choose Authenticate
| Tool | What it does |
|---|---|
find_events | Upcoming events and their URL on every marketplace. Free. |
get_listings | Every listing on one event page, with all-in prices. One capture. |
compare_prices | One event across marketplaces, ranked by all-in price. One capture per marketplace. |
get_seat_map | Section and seat maps, and the cheapest price per section. One capture. |
list_marketplaces | Supported marketplaces and their hosts. Free. |
The tools only read data, and they run on your key, so captures are billed and limited the same as direct API calls. Running compare_prices on an event listed on 4 marketplaces costs 4 captures. A single tool call uses 15 captures at most, and each account can run up to 3 tool calls at once.
Plugins for Claude Code, Codex, Cursor and Gemini, plus an agent skill, are in Tickets-dot-dev/ai on GitHub.
Data use
A capture only reads public data: the listings, prices, fees and seat maps the marketplace shows any visitor on its event page, with no login. Tickets.dev puts no license terms on what a capture returns. Store it, analyze it, build products on it and show it to your own users, with no attribution required.
Questions? Reach us at contact@tickets.dev · Back to Tickets.dev